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