标准浏览器的事件模型是先捕获再冒泡,由于考虑到兼容问题,事件绑定一般都是基于冒泡来做的,那么什么情况下可以考虑利用捕获来做事件绑定呢?
最近在做的课程查找页上报需求的时候,有两个问题要解决:
- 清理之前做的上报
- 重新添加新的上报
如果在原来的基础上直接改当然可以,但是将上报和业务代码耦合显然不是理想的解决方案,由于内嵌的webview是chromium, 不用考虑兼容问题,于是尝试利用捕获来处理。
- 大多数的上报都是点击上报
- 捕获先于冒泡,不用考虑 stopPropagation 的影响
所以可以在最外层,基于捕获来绑定事件:
var getReportKey = function($ele, max) { // 这里需要设置一个 max 值, 避免死循环 max = parseInt(max, 10) || 5; var key = []; var id = ''; do { id = $ele.attr('id'); if (id) { key.push('#' + id); } else { key.push($ele.prop("tagName").toLowerCase()); $ele = $ele.parent(); } } while (!id && --max); return key.reverse().join(' '); }; $('#container')[0].addEventListener('click', function(event) { // 获得鼠标点击的元素 var $target = $(event.target); // 根据该元素获取上报的 key var reportKey = getReportKey($target); var data = null; switch (reportKey) { case '#container h3 a': data = { action: 'title_clk' }; break; // and so on default: break; } data && todoReport(data); }, true);
以上,所有要上报的点都可以在 switch 里完成,同时可以避免和业务逻辑的耦合。
此外,对于页面资源的加载监控等也可以使用捕获来做。