做前端最难受的就是产品给的需求以及测试给的bug了,看待这个标题是不是有点蒙,这是什么需求,下面来解读下!
需求
需求:如下图,点击已保存按钮弹出已保存列表,当点击屏幕其他区域要关闭这个下拉框,是不是很简单
加点东西,但是点击这个下拉框内部的区域不能关闭下拉框)(原谅我里面没写东西你就当有东西,给个机会噻!),是不是很常见,是不是很恶心!你们是怎么做的。 之前我见过有人把事件挂在window
上,然后把不想要操作dom
都挂上class
,然后在点击事件里面一一排除括弧笑,或者有人投机取巧在一部分dom上挂了事件,结果又是测试不是每次都能关闭,全看运气!
接天就来说下我的解决办法,因为我是写的react,我就直接上react代码了,逻辑都是一样,无妨!
挂载事件
首先在componentDidMount
中写下我们函数的触发:
window.addEventListener('click', (event) => {
event = event || window.event;
this.setState({
savedListShow: false, // 这个是控制列表显隐的状态
});
})
事件挂在window上怎么避免点击列表内部的dom不会触发呢,不要说什么阻止冒泡,不好使的,首先我们在事件中输出我们event,
看看到底是什么!
元素挂上不想触发的识别class
这是我点击列表内部输出的event。
说是路径,其实在深一步输出出来的是js对象
,既然是js对象那我们就能拿到对象上的calss属性了,对于我们的判断也就不成问题了。
去代码中到找我们不想要触发的那个(或者是一堆)不想触发的dom的最大父级,
对的我这里是class为SavedList
的div,在最前边(记住是最前边)加上一个class _&saveBtn
(别人不用的,免得冲突)。
点击事件中加判断排除不想触发的dom
在细看下上边我点击输出的event中的path, 每一个元素.
后的就是class, 注意横线处的class,这说明我点击的事件源是我不希望触发的区域,然后我们回到最开始componentDidMount
中的事件函数。
componentDidMount() {
// 点击其他区域关闭已保存条件弹窗
window.addEventListener('click', (event) => {
event = event || window.event;
let isSaveStructure = event.path.some(item => {
这里使用了startsWith,相对来说比较严谨,这要是为什么强调要在最前边添加的原因了
if (item.className && typeof item.className === 'string' && (item.className.startsWith('_&saveBtn') || item.className.indexOf('_&saveBtn') !== -1)) {
return true;
}
});
if (!isSaveStructure) {
this.setState({
savedListShow: false
});
}
})
}
这样依赖我们不想触发的dom以及dom内部的元素,遇到这个点击事件就会呗排除在外了,是不是很省心。
总结
- 添加事件
window.addEventListener('click', (event) => {})
; - 在不想触发的dom的最大父级上添加用于区分的
class
,比如class
为SavedList
的div以及内部dom不需要触发那就在SavedList
上添加需要识别的class
, 主要要避免和其他人的冲突,最好是特殊一点; - 在之前写好的实践中,判断注意
path
里面的是一个数组,包含的是js对象
,抓取返回回来的className
是string
类型,不是数组,我们判断使用的是startsWith();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。