如果笔记

如果笔记

做有价值的技术笔记

性能优化系列2:Vue应用中使用点击事件代理

事件代理,又叫事件委托,主要针对click事件,即只在外层DOM节点上绑定一个原生事件监听函数,然后该DOM节点内发生的click事件都委托给该监听函数处理。事件代理的主要好处就是减少原生事件绑定,原理是利用事件冒泡机制(一个DOM节...

事件代理,又叫事件委托,主要针对click事件,即只在外层DOM节点上绑定一个原生事件监听函数,然后该DOM节点内发生的click事件都委托给该监听函数处理。事件代理的主要好处就是减少原生事件绑定,原理是利用事件冒泡机制(一个DOM节点内所有子节点上发生的点击事件,都会冒泡到该节点上)。 使用事件代理,是性能优化的一个方面。可能我们在一个页面上绑定了很多点击事件监听函数,但实际上会被用户点击触发的可能就那么寥寥几个,所以提前绑定所有监听函数就是性能浪费。使用事件代理可以减少事件绑定数,只有当真实被点击的时候,才去判断该执行什么操作,相当于只做必要的计算。 要实现事件代理,关键点是要实现根据被点击的DOM节点找到对应的处理函数。怎么找到呢?最简单的方式是通过被点击DOM的tagName或className去判断,但这种方式不够灵活。所以一般是自定义一个标签属性,使用它对应到处理函数。 使用事件代理的场景如在页面上有一个列表,列表每一项都有一些点击交互按钮,而且列表还是滚动自动加载,这时候就很有必要使用事件代理。又如页面上某一个模块内有一些点击交互按钮,这时候也适合在该模块上使用事件代理。 那么,在Vue应用中,如何简便地使用事件代理呢? > 此处有一个小问题:Vue的点击事件是绑的原生事件吗?请各位自己去验证它是不是原生事件。(如果已经是事件代理的话我们就没必要再做代理了) 先看看使用示例吧: ```html <ul @click="clickList" k-stop> <li v-for="item in list" :key="item.id"> <a k-name="collect">收藏</a> <a k-name="remove">删除</a> </li> </ul> ``` ```javascript import mapClick from './click'; export default { methods: { clickList: mapClick({ collect(el, target, event) { // el为加了k-name属性的节点,target为事件源节点,event为原生事件对象 // this指向当前Vue实例 alert('collect') }, remove(el) { alert('remove') } }) } } ``` 在最外层ul上绑一个原生事件clickList,同时加上`k-stop`以阻止代理事件冒泡(原生事件依然会冒泡),然后在有交互的节点上加上`k-name属性`,属性值为处理函数名称,与`mapClick`接收的对象参数的属性一一对应。如此已成功使用了事件代理,只在最外层ul上绑了一个原生事件,当动态增加列表项li时,不需要再绑事件。 底层实现函数也是很简洁: ```javascript // 文件 ./click.js export default function (handlerMap) { return function (e) { var target = e.target || e.srcElement; var el = target; var kname; do { kname = el.getAttribute('k-name'); if (kname) { var handler = handlerMap[kname]; if (handler) { handler.call(this, el, target, e); } else { var knames = kname.split(' '), i = 0, len = knames.length; for (; i<len; i++) { handler = handlerMap[knames[i]]; handler && handler.call(this, el, target, e); } } } if (el.hasAttribute('k-stop')) { break; } el = el.parentNode; } while (el && el.nodeType==1); }; } ``` **更多使用提示:** - `k-name`的值可以像class一样有多个,以空格分隔 - `k-name`可以嵌套,阻止代理冒泡只要加上`k-stop`属性 - 要解绑某个节点的处理函数,移出`k-name`属性即可 - 一个Vue组件内可以有多个地方使用事件代理

前端

hahaboy