clickoutside的几种实现
实现
一段最简单的clickoutside方案。其中contains兼容到IE9
function clickOutsideListener(targetDom, clickOutsideFn) {
this.handler = function(e){
if (!targetDom.contains(e.target)){
// Clicked outside the box
clickOutsideFn && clickOutsideFn()
}
}
}
clickOutsideListener.prototype.add = function() {
document.addEventListener('click', this.handler)
};
clickOutsideListener.prototype.remove = function (){
document.removeEventListener('click', this.handler)
}
那么我们在绑定的时候,就会通过类似的代码:
var $ = document.querySelector;
if ($('#menu')) $('#menu').addEventListener('mouseleave', mouseLeaveHandler);
这里要注意,如果你的鼠标移开事件元素内部有如select这一类的元素那可能在部分浏览器(如火狐)会有兼容性问题,解决方案:
function mouseLeaveHandler(e) {
if (e.relatedTarget === null) return;
// handler logic..
}
原因
relatedTarget是鼠标次要事件,因此和鼠标的一些行为(mouse*)密切相关,MDN给出的对应关系请见:
在本次排查中,正是select点开菜单后,在Firefox下,移动到菜单内是一个丢失了relatedTarget的mouse事件,因此可以直接return掉来避免后续执行。
除此以外,mouseover和mouseout著名的bug,即进入mouseover元素的节点,会触发一次mouseout事件和一次mouseover事件,这时就会出现mouseout到里层节点(e.relatedTarget = 里层节点),紧接着mouseover到当前节点(e.relatedTarget = 当前节点),即出现了从自己mouseover到自己的bug。
其他实现
使用的composedPath,兼容到IE11,如果需要更好的兼容性请见:https://gist.github.com/sibbng/13e83b1dd1b733317ce0130ef07d4efd