iOS safari BUG 总结
safari对DOM中元素的冒泡机制有个奇葩的BUG,仅限iOS版才会触发~~~
BUG重现用例请见线上DEMO: 地址
bug表现与规避
在进行事件委托时,如果将未存在于DOM的元素事件直接委托到body上的话,会导致事件委托失效,调试结果为事件响应到body子元素为止,既没有冒泡到body上,也没有被body所捕获。但如果事件是DOM元素本身具有的,则不会触发bug。换而言之,只有元素的非标准事件(比如click事件之于div)才会触发此bug。
因为bug是由safari的事件解析机制导致,无法修复,但是有多种手段可以规避
如何避免bug触发:不要委托到body结点上,委托到任意指定父元素都可以,或者使用原生具有该事件的元素,如使用click事件触发就用a标签包一层。
已触发如何修补:safari对事件的解析非常特殊,如果一个事件曾经被响应过,则会一直冒泡(捕获)到根结点,所以对于已大规模触发的情况,只需要在body元素的所有子元素绑定一个空事件就好了,如:
("body > *").on("click", function(){};);
可能会对性能有一定影响,但是使用方便,大家权衡考虑吧~~~
事件委托机制的小研究
对于事件委托,有人认为可以用addEventListener第三参数来控制,其实究其根本,事件冒泡与委托机制关系并不大。从沟通中看出来相当多的一部分人认为第三参数的作用是控制事件是否冒泡到根结点,其实从官方解释来看,他的作用是控制事件触发在捕获阶段还是冒泡阶段。也就是说,如果根本不存在事件冒泡这个机制,事件委托依然是可以完成的,为什么呢?
还有事件捕获啊,况且这个才是W3C标准。
最初本来就是没有冒泡的,IE为了某些大家都懂的目的,把捕获过程反过来"创造"出了冒泡机制,所以事件响应的机制其实是:由外到内的捕获->元素本身事件->由内到外的冒泡。所以同理,stopPropagation()方法也不仅仅是针对冒泡,而对事件在捕获阶段也同样有效果,简而言之,就是阻止把事件分派到其他节点,被其它所节点响应。
但是由于某些历史原因,虽然规范明确要求捕获阶段不会涉及事件目标,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果就是有两个机会在目标对象上操作事件。
所以事件委托其实是由event.target来实现的,冒泡只不过其中一种传递事件的方案而已,兼容性好。
哎,IE啊……