JS 点击某元素以外的地方触发事件
ヤッハロー、Kaiqisanすうう、一つふつうの学生プログラマである,在半年前让我十分头疼的问题,自从我开始正式学习event事件和DOM之后,我:就这?就这?
解决这个问题的核心关键还是利用event对象
现在有HTML代码如下
<div style="width: 400px;height: 300px;border: 1px solid #000000;
margin: 10% auto 0 auto; text-align: center" class="demo">
<p>测试界面</p>
</div>
<div class="status">事件触发情况:未开始</div>
现在的需求就是点击测试界面以外的区域触发我想要触发的事件。
document.addEventListener('mousedown', (e) => {
console.log(e);
})
获取一个全局的监听事件,到了这个时候,答应我,不要使用坐标(clientX offsetTop等等的),因为使用坐标的话在计算上是非常麻烦的,因为您不知道一些大项目里面的HTML代码的结构是多么的错综复杂。
到了这个时候,我们应该打开浏览器,获取点击事件之后请一定要打开看一下!找一下里面有什么属性是可以加以利用的。(这里只讲关键的,不讲解全部的event对象里的所有属性参数方法)
找了一圈,发现这俩属性是有用的
target
: 当前点击元素的DOM信息(在其他事件里面就是派发事件的目标元素)path
: 这里汇集了触发事件的DOM元素和其上层的节点的DOM信息(这会一直追溯到Window),它获取到的内容和下面方法获取到的内容是完全一样的。
document.addEventListener('mousedown', (e) => {
console.log(e)
})
let a = document.getElementsByClassName('demo')[0]
let arr = []
arr.push(a) // 先推入当前元素
getParent(a) // 执行递归
arr.push(window) // 最后再加一个window
function getParent(obj) {
if (obj.parentNode) {
// 往树的上层追溯,直到最上层
arr.push(obj.parentNode)
} else {
return
}
getParent(obj.parentNode) // 递归追溯源头
}
现在,有了这俩元素之后,接下来,我们该咋用嘛,我们先放代码,然后再讲解!
let ObjStatus = document.getElementsByClassName('status')[0]
document.addEventListener('mousedown', (e) => {
let t = document.getElementsByClassName('demo')[0] // 最外层元素
if (!e.path.includes(t)) {
ObjStatus.innerHTML = '事件触发情况:触发'
} else {
ObjStatus.innerHTML = '事件触发情况:未触发'
}
})
这样之后,点击目标区域之外才可触发事件。
原理讲解
本来就只是使用e.target
就行了,但是点击事件的target的机制问题,单纯地使用e.target
并不能根本解决这个问题,因为目标区域内可能有很多的元素,这个点击事件会选择其内部的元素,就举当前的html代码为例子,现在我的目标区域demo内有一个p标签,如果我点到这个p标签,e.target会指向这个p标签,而不会去指向这个demo元素。又因为这个e.path
含有当前元素和其所有的祖宗元素,所以可以查找e.path
是否有这个demo元素,如果有,那么这个元素就是属于demo元素的内部的元素(这需要排除一些特殊情况,比如绝对布局和使用了transform的元素。),那就是说,如何点击了demo元素外的其他元素,那么当前捕获的e.path里面绝不会有demo元素。
总结
这个功能多用于关闭自己设置的弹窗,设置好最外层的判断元素,点击弹窗之外,弹窗就会关闭,这个在用户体验方面是非常有利的一个功能。