事件委托
假如我们希望实现一个功能,希望我点击ul中的li元素让它执行某个函数,应该怎么写?
ul.addEventListener('click',function(e){
if(e.target.toLowerCase()==='li'){
fn()
}
})
这样写是有明显的bug的,如果用户点击的是 li 里面的 span,就没法触发 fn,这显然不对。所以如果li有span的话,我们就需要判断span的父元素中有没有li,如果有的才会执行函数,如果没有就不执行函数。
所以应该这样写,这样写的思路在于,如果,我点击的li中是有其他元素(span)的,那么只要它是我希望点击元素(span)的子元素,函数就会执行。所以我们要递归的去找到当前点击元素的父元素,当父元素是是我们要点击的元素(li)时执行fn。如果一值到头(ul)都找不到,那么说明(ul)中没有(li)那么函数就不会执行。
ul.addEventListener('click',function(e){
// 获取当前元素,这个元素可能是li,也可能不是
let e1 = e.target
// 当这个元素不是li的时候
while(!e1.matches(li)){
if(ul === e1){
e1 = null
break
}
//遍历它的父元素
e1 = e1.parentNode
}
// 直到e1的父元素是li时才执行
e1 && fn()
})
下面是事件冒泡的同用版本
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
拖拽事件
var dragging = false
var position = null
xxx.addEventListener('mousedown',function(e){
dragging = true
// 记录刚开始拖拽时候的位置
position = [e.clientX, e.clientY]
})
document.addEventListener('mousemove', function(e){
if(dragging === false){return}
const x = e.clientX
const y = e.clientY
const deltaX = x - position[0]
const deltaY = y - position[1]
const left = parseInt(xxx.style.left || 0)
const top = parseInt(xxx.style.top || 0)
xxx.style.left = left + deltaX + 'px'
xxx.style.top = top + deltaY + 'px'
//更新这个位置
position = [x, y]
})
document.addEventListener('mouseup', function(e){
dragging = false
})
这里要注意的地方有下面几点
1.监听的不是div而是document,不然移动快了的话,可能会掉
2.设置style的时候要加上px,获取的鼠标的坐标也要先转换成数字
3.一开始的时候style还没有top和left,所以如果没有先设为0