事件委托
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父结点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫事件委托。
事件委托的优点
减少内存消耗,提高性能
对于如下代码
<div class='buttons'> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> </div> 复制代码
现需要在点击每个 button 时响应一个事件,如果给每个 button 都绑定一个函数,那么会消耗较多的内存。借助事件委托,只需要将监听函数定义在父元素 div 上,这样不管点击的是哪一个 button 标签,遵循冒泡的传递机制,都会响应事件。
可以监听动态元素
很多时候,用户的一些操作会增删某个子元素,如果一开始给每个子元素绑定事件,那么在子元素发生变化是,就需要给新增元素绑定事件,给要删除的元素解绑事件,使用事件委托就会省去很多类似的麻烦。
事件委托的实现:
<div id='container'> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> </div> <script> container.addEventListener('click', function(e){ //把目标元素赋值给t let t = e.target //判断是否匹配目标元素 if (t.matchs('button')) { console.log('这是:' + t.textContent); } }; </script> 复制代码
这样点击 button 时会触发事件,打印出相应元素的文本内容。
基于此,可以封装一个事件委托函数
on('click', '#container', 'button', ()=>{ console.log('这是:' + t.textContent) }) function on(eventType, element, selector, fn) { //判断是不是 Element //如果传进来的是选择器,不是 Element 本身,就先变成 Element //因为只有 Element 才能监听事件 if (!(element instanceof Element)) { element = element.querySelector(element) } parentElement.addEventListener(eventType, (e)=>{ let target = e.target if (target.matches(selector)) { fn(e) } }) } 复制代码
当被点击的元素有多个层级时,则需要递归判断其祖先元素,直到找到监听的元素(注意限定判断范围)
on('click', '#contaniner', 'button', ()=>{ console.log('用户点击了li') }) function on(eventType, element, selector, fn) { if (!(element instanceof Element)) { element = document.querySelector(element) } element.addEventListener(eventType, (e)=>{ let el = e.target // 如果匹配到了selector就跳出循环 while(!el.matches(selector)){ if (el === element){ //已经找到了父元素,说明还没找到,就设置为null el = null break } el = el.parentNode } // 找到了el, 就调用函数 el && fn.call(el, e, el) }) }
作者:易安_Ian
链接:https://juejin.cn/post/7022458263920705544