1.什么是事件流?
事件流描页面中接收事件的顺序,简单来说就是事件从捕获-->处理-->冒泡的一个过程。事件冒泡触发顺序是从下至上,事件捕获的触发顺序是从上至下。(先捕获后冒泡)。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。
2.什么是事件冒泡?
事件冒泡是事件传递方式的一种现象,就是🐟吐泡泡一样肯定是慢慢由水底浮到水面,事件传递顺序是自身dome 》 父dom 》body 》html 》window。
3.什么是事件委托?
事件委托是利用事件冒泡的特性,将本应该注册在子元素上的处理事件注册在父元素上,触发子元素时发现其本身没有相应事件就转而触发父元素的事件。
优点:
- 减少DOM操作,提高性能。
- 添加的子元素会自动有相应的处理事件。
缺点:
- 事件委托基于冒泡(部分浏览器不支持 IE)。
- 层级过多,冒泡过程中可能被中间层阻止,事件过多时判断复杂 。
4.事件委托写法
el.addEventListener("click", function(){
console.log('事件委托-方法')
});
el.addEventListener('click', {
handleEvent: function (event) {
console.log('事件委托-EventListener接口对象');
}
});
//IE 8 及更早 IE版本兼容写法
var x = document.getElementById("myBtn");
if (x.addEventListener) x.addEventListener("click", myFunction);
else if (x.attachEvent) x.attachEvent("onclick", myFunction);
// 移除事件
function removeEvent (element, type, handler) {
if (element.removeEventListener) element.removeEventListener(type, handler, false);
else element.detachEvent('on' + type, handler); //it
},
// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation (ev) {
if (ev.stopPropagation) ev.stopPropagation();
else ev.cancelBubble = true; //ie
},
// 取消事件的默认行为
function preventDefault (event) {
if (event.preventDefault) event.preventDefault();
else event.returnValue = false; //ie
},
addEventListener有三个参数分别是:
- type :监听事件类型(事件类型大全)
- listener :监听事件触发回调(方法或者EventListener接口对象)
- 参数三有两种版本
- options (古老的版本目前基本肯定不会遇到-了解下没有坏处)
- capture :listener会在该类型的事件捕获阶段传播到该EvenTarget时触发
- once:listener在添加之后最多被调用一次
- passive:true时,listener永远不会调用preventDfault()
- mozSystemGroup:listener被添加到systemgroup
- useCapture:是否要先于下面的EventTarget调用该listener()。true回调在捕获阶段执行,false事件在冒泡阶段执行。
- options (古老的版本目前基本肯定不会遇到-了解下没有坏处)
高级写法
function delegate(element, eventType, selector, fn) {
function addParent(){
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
}
if(element.addEventListener){
element.addEventListener(eventType, e => {
addParent();
},false )
}else{ //ie
element.attachEvent('on'+eventType, e => {
addParent();
},false )
}
return element
}
delegate(document.getElementById('1'), 'click', 'ul', function() {
alert($(this).text());
});
5.vue中的事件委托
vue交流社区中有人提问后大佬给出的解答 Is event delegation necessary?。vue内部是没有处理事件委托的。并且转换为虚拟dom的时候也并未有相关处理(这里建议大家自己去阅读下源码,我看的有点久了已经记不清楚了)。
//建议写法,听过data-index来区分
<ul @click="uLClick">
<li v-for="(item, index) in list" :data-index="index">{{index}}</li>
</ul>
6.后续补充vue虚拟dom转换源码,及vue事件处理源码