1. 作业
1.1 购物车案例
javascript
// 1. 进入页面之后渲染数据
const arr = JSON.parse(localStorage.getItem('car')) || dataArr
const box = document.querySelector('.tbody')
// 封装一个render函数
const render = function(){
const trArr = arr.map(function(el, i){
return `
<div class="tr">
<div class="td"><input type="checkbox" ${el.isChecked ? 'checked': ''} /></div>
<div class="td"><img src="${el.icon}" alt="" /></div>
<div class="td">${el.price}</div>
<div class="td">
<div class="my-input-number">
<button class="decrease"> - </button>
<span class="my-input__inner">${el.num}</span>
<button class="increase"> + </button>
</div>
</div>
<div class="td">${el.price * el.num}</div>
<div class="td"><button class="del" data-id="${i}">删除</button></div>
</div>
`
})
// 把map方法返回的数组,转为字符串拼接
box.innerHTML = trArr.join('')
}
render()
// 2. 删除
box.addEventListener('click', function(e){
if (e.target.className === 'del'){
console.log(e.target.dataset.id)
const res = confirm('你确定要删除吗')
if (res) {
arr.splice(e.target.dataset.id, 1)
render()
localStorage.setItem('car', JSON.stringify(arr))
}
} // end if
})
1.2 微博发布案例
javascript
// 1. 进入页面获取本地存储的数据
const arr = JSON.parse(localStorage.getItem('weibo')) || []
// 2. 渲染评论
const list = document.querySelector('#list')
function render(){
const newArr = arr.map(function(el,i){
return `
<li>
<div class="info">
<img class="userpic" src="${el.img}" />
<span class="username">${el.name}</span>
<p class="send-time">发布于 ${el.time}</p>
</div>
<div class="content">${el.msg}</div>
<span class="the_del" data-id="${i}">X</span>
</li>
`
})
list.innerHTML = newArr.join('')
}
render()
// 3. 发布评论,新增数据
const btn = document.querySelector('#send')
const area = document.querySelector('#area')
btn.addEventListener('click', function(){
// 1. 随机获取头像和名字
const random = Math.floor(Math.random() * dataArr.length)
arr.unshift({
img: dataArr[random].imgSrc,
name: dataArr[random].uname,
msg: area.value,
time: new Date().toLocaleString()
})
console.log(arr)
// 渲染
render()
area.value = ''
// 存到本地
localStorage.setItem('weibo', JSON.stringify(arr))
})
// 3. 删除功能 事件委托
list.addEventListener('click', function(e){
if (e.target.className === 'the_del'){
// console.log(e.target.dataset.id)
arr.splice(e.target.dataset.id, 1)
render()
localStorage.setItem('weibo', JSON.stringify(arr))
} // end
})
2. 放大镜案例
2.1 鼠标经过小图片,左侧中图片跟随变化
- 在这个案例中,所有的盒子用的img都是一样的,中等盒子,小盒子,大盒子中img 同一张
- 使用mouseover给公共父元素绑定事件,mouseover有事件冒泡
- 判断谁触发的事件的时候,判断的是IMG,为什么?因为这样我们可以更方便的获取到触发图片的src,待会儿要使用,赋值给中等盒子的图片
- 怎么获取中等盒子里面的img元素,这里使用了 children 获取子元素,注意是一个伪数组,还要用下标才能取到img
- 排他的时候,是给小图片的父元素 li标签添加active类名,注意 parentNode
javascript
// 1. 获取元素
const middle = document.querySelector('.middle')
const small = document.querySelector('.small') // 公共父元素
// 2. 给公共父元素绑定事件 mouseover => 它有事件冒泡
small.addEventListener('mouseover', function(e){
console.log(e.target)
if (e.target.tagName === 'IMG'){
// 2.1 给当前小图片的父元素li标签添加active
small.querySelector('.active').classList.remove('active')
e.target.parentNode.classList.add('active')
// 2.2 取到小盒子中的图片,给左侧中等盒子
console.log(e.target.src)
console.log(middle.children)
middle.children[0].src = e.target.src
} // end if
})
2.2 鼠标经过中盒子,显示右侧大盒子和遮罩层
javascript
// 鼠标经过中等盒子,显示右侧大盒子和黑色遮罩层
// 1. 获取元素
const large = document.querySelector('.large')
const mask = document.querySelector('.layer')
// 2. 注册事件,给middle盒子注册 经过和离开 mouseenter / mouseleave
middle.addEventListener('mouseenter', function(){
large.style.display = 'block'
large.style.backgroundImage = `url(${middle.children[0].src})`
mask.style.display = 'block'
})
middle.addEventListener('mouseleave', function(){
large.style.display = 'none'
mask.style.display = 'none'
})
2.3 黑色遮罩层跟随鼠标移动
e.offsetX, e.offsetY 可以获取鼠标相对于盒子的坐标 把这个坐标赋值给mask,当鼠标移动的时候,遮罩层也就移动了 (注意mask有定位,才能设置left, top)
javascript
// 黑色遮罩层,跟随鼠标移动(鼠标在middle盒子中移动)
middle.addEventListener('mousemove', function(e){
console.log(e.offsetX, e.offsetY)
// 声明x,y 表示黑色遮罩层的x,y坐标
let x = e.offsetX
let y = e.offsetY
mask.style.left = x + 'px'
mask.style.top = y + 'px'
})
- 鼠标移动的时候,有闪动的情况,是因为,offsetX可能会取到鼠标相当于黑色遮罩层的位置,也可能取到鼠标相对于middle盒子的位置,赋值给mask,就会出现问题
- 我们要做的就是不让获取鼠标相对于黑色盒子的坐标,可以通过css将黑色遮罩层的鼠标事件设置为none
css
/* 解决闪动的问题 */
/* 不对鼠标事件做出反应 */
pointer-events: none;
/* 让鼠标变为移动的图标 */
cursor:move ==> 给middle盒子加
2.4 让鼠标位于遮罩层中心
- 鼠标距离中等盒子的坐标 e.offsetX, e.offsetY => 鼠标的位置
- 遮罩层的横坐标和纵坐标 ,我们用 x, y 表示
思考? 遮罩层的横坐标x 和 鼠标的位置e.offsetX的关系
x = e.offsetX - 遮罩层宽度的一半 => 可以让鼠标位于遮罩层中心
=> 通过鼠标在中等盒子中的坐标,求到黑色遮罩层在中等盒子中的坐标
javascript
// 黑色遮罩层,跟随鼠标移动(鼠标在middle盒子中移动)
middle.addEventListener('mousemove', function(e){
console.log(e.offsetX, e.offsetY)
// 声明x,y 表示黑色遮罩层的x,y坐标
// 让e.offsetX当前鼠标的位置 - 遮罩层宽度的一半 得到的x赋值给遮罩层,
let x = e.offsetX - mask.offsetWidth / 2
let y = e.offsetY - mask.offsetHeight / 2
mask.style.left = x + 'px'
mask.style.top = y + 'px'
})
2.5 限定黑色遮罩层移动的位置
javascript
// 黑色遮罩层,跟随鼠标移动(鼠标在middle盒子中移动)
middle.addEventListener('mousemove', function(e){
console.log(e.offsetX, e.offsetY)
// 声明x,y 表示黑色遮罩层的x,y坐标
// 让e.offsetX当前鼠标的位置 - 遮罩层宽度的一半 得到的x赋值给遮罩层,
// let x = e.offsetX
// let y = e.offsetY
let x = e.offsetX - mask.offsetWidth / 2
let y = e.offsetY - mask.offsetHeight / 2
const maxX = middle.offsetWidth - mask.offsetWidth
const maxY = middle.offsetHeight - mask.offsetHeight
console.log(x, y)
// 怎么让黑色遮罩层限制在中等盒子中移动
x = x < 0 ? 0 : x
x = x > maxX ? maxX : x
y = y < 0 ? 0 : y
y = y > maxY ? maxY : y
mask.style.left = x + 'px'
mask.style.top = y + 'px'
// 让大盒子背景图片跟随遮罩层扫过的位置移动
})
2.6 大图片背景图跟随鼠标移动
中等盒子 宽高 400 * 400 大盒子背景图 800 * 800 当黑色遮罩层在中等盒子移动1px, 大盒子背景图应该移动2px,存在一个2倍关系 另外,鼠标往右移动,背景图应该是往左移动的,所以需要加负号
javascript
// 黑色遮罩层,跟随鼠标移动(鼠标在middle盒子中移动)
middle.addEventListener('mousemove', function(e){
// 省略 。。。。
// 如果黑色遮罩层在中等盒子中移动了1px, 那么右侧大盒子中的背景图相对要走2px
// large.style.backgroundPositionX = - 2 * x + 'px'
// large.style.backgroundPositionY = - 2 * y + 'px'
large.style.backgroundPosition = `${- 2 * x}px ${- 2 * y}px`
})