1. DOM事件模型
前半部分,事件从最外面的父div依次传递到最里面的后代div,1-2-3-4这部分我们叫捕获过程。
之后事件又从最里层的后代div逐层传出,4-3-2-1这部分我们叫冒泡过程。
- addEventListener第三个参数可以不传,默认是false,这个参数控制是否捕获触发。
所以我们只传两个参数时,这个事件是冒泡传递触发的,
当第三个参数存在且为true时,事件是捕获传递触发的。
x.addEventListener('click', function(){
console.log('冒泡')
})
x.addEventListener('click', function(){
console.log('捕获')
},true)
- 事件冒泡
- 事件捕获
- 如果这个元素是被点击的元素,那么捕获不一定在冒泡之前,顺序是由监听顺序决定的
- 扩展
阻止冒泡和捕获: w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
取消默认事件: w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
2. 移动端触摸事件
- touchstart touchmove touchend touchcancel
- 模拟 swipe 事件:记录两次 touchmove 的位置差,如果后一次在前一次的右边,说明向右滑了。
3. 事件委托
- 假设父元素有4个儿子,我不监听4个儿子,而是监听父元素,看触发事件的元素是哪个儿子,这就是事件委托
- 可以监听还没有出生的儿子(动态生成的元素)。省监听器。
<ul>
<li><span>点击<span></li>
<li>点击</li>
</ul>
---------------------------------------------------
//错误版
ul.addEventListener('click', function(e){
if(e.target.tagName.toLowerCase() === 'li'){
fn() // 执行某个函数
}
})
//高级版
var elementUl = document.querySelector('ul');
function fn(event) {
var el = event.target;
while (el.tagName !== 'LI') {
if (el === elementUl){
el =null;
break;
}
el = el.parentNode;//返回當前元素的父节点
}
if (el) {
console.log(el)
}
}
elementUl.addEventListener('click', 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
}
思路是点击 span 后,递归遍历 span 的祖先元素看其中有没有 ul 里面的 li