关于自定义select打开后点击页面其他地方关闭的一些总结
点击打开一个弹层,然后点击其他地方关闭的需求我们做客户端的应该是经常遇到的需求,这里主要是我个人总结出来的一些方法:
1.第一种,只有点击打开按钮才能关闭
这个就没什么好说的,点击按钮,做对应操作,十分简单,不过体验也同样差。
点开选择框之后只有点击打开选择框的按钮才能关闭。
2.第二种,在选择框后,其他元素之前加上一个蒙版
蒙版加上之后,可以是透明的,也可以是半透明的,不过一个选择框加个半透明的蒙版有点不伦不类。
这样基本的点击其他位置关闭选择框的功能是实现了,但是有个致命的缺点,就是你点击其他地方是没有效果的。
因为你第一次点击的是蒙版,所以其他地方并没有背点击,体验感很差。
3.第三种,加全局点击事件
这个方法基本就可以实现了点击按钮打开选择框,点击其他位置关闭选择框,呃,来看看代码:
this.showList = !this.showList; if(this.showList){ var _this = this; setTimeout(function () { var windowClick = window.onclick; window.onclick = function(e){ _this.showList = false; if(windowClick){ windowClick(e); } window.onclick = windowClick; }; },0); }
在选择框打开的时候顺便给一个一次性的window.click事件下次不管点击哪里都会触发,然后关闭选择框。
但是这样写也会有一些问题,就是在一些阻止冒泡的dom上边触发click事件的时候,并不会关闭选择框。
修正:
例子中使用window.onclick = function这种方式来做的,建议使用window.addEventListener方式添加事件,这样就不需要保存原click事件这么麻烦了,不过如果是单页面应用,需要在组件注销的时候,移除事件监听。
例子中时用了onclick方法,后来发现,参考element-ui的方式,使用mouseup事件更好,因为一般我们会对dom绑定click事件,阻止冒泡以后并不会影响到mouseup事件。
以在vue中举例:
mounted() { window.addEventListener('mouseup', this.hideList) }, methods: { handleList(){ this.showList = !this.showList; }, hideList(){ if(this.showList){ this.showList = false; } } }, beforeDestroy() { window.removeEventListener('mouseup', this.hideList) }
4.第四种,打开选择框的元素触发blur事件
blur事件是一部分元素的事件,所以需要在点击打开选择框的元素上添加一个属性:tabindex="-1"。
普通元素加上tabindex属性之后就可以拥有focus和blur事件,这样就可以完美实现点击其他位置关闭选择框的目的了。
给值-1是因为防止按tab键选中这个元素,当然也可以给正值,这个属性的值代表的是按tab键选中此元素的顺序,感觉和z-index理解差不多数字越小越靠前选中(0除外,0是最后一个被选中,但是也有focus和blur事件)。
最后附上测试的代码:
<div class="vueApp"> <div tabindex="2" @focus="console('div tabindex=“2” focus')" @blur="console('div tabindex=“2” blur')">tabindex="2"</div> <el-input @focus="console('input focus')" v-model="input"></el-input> <div tabindex="-1" @focus="console('div tabindex=“-1” focus')" @blur="console('div tabindex=“-1” blur')">tabindex="-1"</div> <div @focus="console('div not tabindex focus')" @blur="console('div not tabindex blur')">not tabindex</div> <div tabindex="1" @focus="console('div tabindex=“1” focus')" @blur="console('div tabindex=“1” blur')">tabindex="1"</div> <div tabindex="1" @focus="console('div tabindex=“1” focus')" @blur="console('div tabindex=“1” blur')">tabindex="1"</div> <div tabindex="0" @focus="console('div tabindex=“0” focus')" @blur="console('div tabindex=“0” blur')">tabindex="0"</div> </div>
new Vue({ el:".vueApp", data:{ input:"13212" }, mounted:function(){}, methods:{ console:function (str) { console.log(str); } } })