仿制目标
目标效果:需要一个下拉按钮的样式(实际不是按钮,可以用背景图来实现),选中之后将内容传给select并聚焦,同时下拉栏消失。鼠标悬停在列表内的元素上有样式变化。
思路:
这个文本框明显可以用input元素text代替,传值用JS也很好解决,为了不让内容可以手动输入可以对文本栏设定一个.setAttribute(“readOnly”, true);。至于下拉栏,用一个ul元素加上绝对定位就可以做到。实现过程中遇到的真正的麻烦是让下拉栏消失。
方法一:
- 首先做一个div.main来装input,通过定义背景图片让下拉箭头样式固定到正确的位置。
- 将ul写好,定好li大小,将ul绝对定位到div下方。
- 再写一个固定定位div.cover,定义div.main的z-index=100;div.cover的z-index=98 display=none width=100%,height=100%;ul的z-index=99。
- 用JS来控制ul和div.cover的消失和出现,原理都是改变样式中的display。在div.cover的点击事件中让ul消失就好了,至于input的点击事件中的改变ul的逻辑就不赘述了。
- 这个方法有一个致命的问题,也是和select最大的区别,一旦下拉框被input的点击触发,那么同时出现的还有透明的div.cover,这个覆盖了除了下拉列表以外的几乎整个视窗,虽然可以实现点击其他地方,下拉框消失,但是同时也直接无法点击到其他元素了,必须要先触发div.cover的点击事件中的自我隐藏后,才能点击其他的元素,这和目标效果有明显的差别,看起来像,用起来还是有差别的,所以我想到了方法2。
方法2:
- 分析:点击其他区域隐藏下拉列表主要就是两种事件的触发,input[type=“text”]的失焦,或者某种元素的点击,方法一用元素的点击显然不尽人意,所以我决定用onblur事件来尝试。
- 样式部分和方法一一致,主要问题是如何用JS设计逻辑使其能够判断失焦时,鼠标点击的是下拉框以外的位置,这个问题之所以重要是因为我发现如果不加以判断,只要失焦就让下拉列表消失,那么下拉列表的内容就一直点不到,因为在点击时input的失焦事件先触发,ul做的下拉列表就直接隐藏了。
- 所以我开始尝试设置一个变量来判断ul的内容是否被点击过,但是这种尝试是徒劳的,如果点击过之后执行的语句和未点击过执行的语句是一模一样的,多加一个判断也不能让ul的点击事件优先执行,这里我甚至想为每个事件设置一个优先级,先调用什么,再调用什么,我对JS不太熟悉,显然这种方法不太适合我。
- 最后我决定用onmouseover和onmouseout事件来解决这个问题,同时也用到了一些DOM冒泡的好处。
代码:
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
position: relative;
width: 500px;
height: 35px;
margin: auto;
}
input {
width: 500px;
height: 35px;
outline: none;
cursor: default;
background-image: url("./selectBtn.png");
background-repeat: no-repeat;
background-position: 459px -1px;
border: 1px solid #ddd;
}
input:focus {
border: 1px solid lightblue;
}
ul {