今天想给大家分享一下之前自己做的一个js模拟下拉框,所有select-option中我能发现的操作,都在我的代码中将其实现,希望对大家有所帮助。如果select中还有一些本人未实现的希望大家在评论区指出。话不多说,直入主题。
div id = "box">
<p>p>
<ul>
寒冰射手 艾希li>
<li>德玛西亚之力 盖伦li>
<li>无极剑圣 易li>
<li>流浪法师 瑞兹li>
<li>战争女神 希维尔li>
<li>德邦总管 赵信li>
ul>
div>
我在这里用的是ul>li进行布局,并用一个div将其包裹,p标签是显示选择的li中的文本。
以下是style样式:
<style>
*{margin:0; padding:0;}
li{list-style:none;}
#box{margin:50px 0 0 50px;}
#box p{width:202px; height:30px; border:1px solid #999; padding-left:10px; font:16px/30px ""; box-sizing:border-box;}
#box p:hover{cursor:default;}
#box ul{display:none; border:1px solid rgb(47, 140, 245);}
#box ul li{width:200px; height:30px; padding-left:10px; font:16px/30px ""; box-sizing:border-box;}
#box ul li:hover{cursor:default;}
#box ul li.active{background:rgb(0, 153, 255); color:#fff;}
style>
浏览器显示结果如下:
p标签里默认存放的是下拉框中的第一条,默认ul>li是不显示的。
布局就说到这里,本来不想多说关于布局,但是还是放出来希望对大家有所帮助。
(1)第一步,不用多说肯定是要获取元素。这里需要获取的元素为p、ul、li
//获取元素
var op = document.querySelector("p");
var oul = document.querySelector("ul");
var oli = document.querySelectorAll("li");
(2)第二步,将初始效果显示出来,如上图所示
// 定义index,indexC的初始值为0
var index = 0, indexC = 0;
//把li的第一个显示在p标签内
op.innerHTML = oli[0].innerHTML;
oli[indexC].className = "active";
//这里索引用哪个都可以,要与后续保持一致即可
这里为何定义需要定义两个索引,后面涉及到的时候再说。
(3)给p添加点击事件
op.onclick = function (eve) {
var e = eve || window.event;
//解除冒泡
stopBubble(e);
//改变p边框的样式
op.style.border = "2px solid rgb(47, 140, 245)";
op.style.borderRadius = "2px";
[注意] 我直接按照我的思路往下阐述(代码顺序自行把控),若是使用我的代码注意补齐**{}**等符号,很多注释都在代码中有所体现。
-----在点击p标签的同时,也会影响到ul的显示隐藏,而ul的显示隐藏,不仅仅是点击p,点击ul和点击document以及回车都会对其的显示隐藏有影响。
-----首先点击p标签激活下拉框,显示ul。之后可以继续点击p、ul,按回车键隐藏ul。此时下拉框仍处于激活状态。
-----只有点击了document的时候才会阻止所有可以对p中元素改变的操作。
(我在点击的时候改变了边框样式,这样就好判断下拉框是否处于激活状态)
下面我定义了两个状态a、b,分别对应非激活状态与激活状态。当为0时,点击显示、为1时点击隐藏。
var a = 0, b = 0;
//定义a,b两个状态。当a、b为0状态时,使ul显示。 b = 1时使ul消失。
if (a == 0 || b == 0) {
oul.style.display = "block";
a = 1;
b = 1;
} else if (b == 1) {
oul.style.display = "none";
b = 0;
}
(4)当ul显示的时候,首先我们可以通过滑动鼠标,改变li样式,表示当前鼠标所在的li,滑动鼠标的时候,仅仅改变li的样式。只有当鼠标按下的时候才会将当前选中的li的元素在p中显示。(激活状态)
for (var i = 0; i < oli.length; i++) {
//添加索引
oli[i].index = i;
//给li添加鼠标移动事件
oli[i].onmousemove = function () {
for (var j = 0; j < oli.length; j++) {
//清除所有样式
oli[j].className = "";
}
//给当前的li添加类名“active”
this.className = "active";
//点击li使点击的li的内容显示在p中,并使ul消失,状态为b = 0;
this.onclick = function (eve) {
var e = eve || window.event;
stopBubble(e);
oul.style.display = "none";
b = 0;
op.innerHTML = this.innerHTML;
this.className = "active";
indexC = index; //tips:
}
//将点击的li的索引返回,之后会需要再次使用鼠标移动改变的li的索引,所以要将index返回出来。在后面需要使用的时候可以获取到
return index = this.index;
}
}
tips:
1.这里为何要将index的值赋给indexC呢,因为我们在点击li的时候,ul隐藏,当我们再次点击p显示ul的时候,具有样式的li的元素还是得保证和p中的元素一致。
2.那么肯定有人有疑惑,为什么不将li的索引直接设置为indexC,而偏偏要多此一举多设置一个index呢。
因为会有这样一个问题,一开始index为0,对应显示的是寒冰射手,如果你将鼠标移动至德玛西亚之力不通过点击li使其消失。而直接点击document,这时候p获取的是寒冰射手的indexC=0,而此时li的样式设置给了德玛西亚之力,这时候你再次点击p,显示的是寒冰但li选中的却是德玛.会出现这样一个问题。
//封装的解决事件冒泡的兼容处理
function stopBubble(e){
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
}
(5)继续分析点击doocument,停止一切对p改变的操作(非激活状态)
//点击document,改变ul,p的样式并将a的状态赋值为0。
document.onclick = function () {
oul.style.display = "none";
op.style.border = "1px solid #999";
for (var j = 0; j < oli.length; j++) {
//清除所有样式
oli[j].className = "";
}
oli[indexC].className = "active";
//获取到点击document隐藏时,p中显示的是indexC的索引
index = indexC;
//如果是点击li的话,会将li的index赋给indexC,若点击document则表示,未改变实际的li。
//li的样式应该还是在p元素对应的li上,所以将indexC再赋给li的索引index
a = 0;
}
以上代码都是在点击p的事件中的。
[提示]: 大家可以这么理解:
indexC的索引是p元素显示的选中的对应的li的索引,在p中要显示你要展示的li,那么就将此li的index赋值给indexC。
index的索引则是具有样式的li,并非是点击选中的li的索引。因为鼠标滑动只改变样式,并没有将滑动的时候具有样式的li的值显示在p中。
设置index与indexC就是为了解决:鼠标移动改变的li并不就是要显示的在p中的li。用这俩索引将只具有鼠标样式的li,和实际被选中的li区别出来。保证不会相互造成影响。
index改变li的样式,如果要将当前具有样式的li显示在p标签中,就将index赋值给indexC。
点击p显示ul的时候将indexC赋值给index,使与p的属性相同的li添加样式。
(6)接下来就是键盘的上下键、回车键操作,改变li的样式和p的显示
上面说的有俩状态,为什么要说到会有激活状态与非激活转态,在键盘事件中就会有所体现。
----非激活状态,不能通过键盘改变
document.onkeydown = function (eve) {
//a的值为0时,表示点击document使ul消失,不能执行键盘事件
if (a == 0) {
index = indexC;
document.onkeydown = null;
----激活状态,ul不论是显示还是隐藏,都可以使用键盘操作ul的显示、p标签中元素的改变。
①上键
} else if (a == 1 || b == 1 || b == 0) {
//当状态为三者任意一个的时候可以执行键盘事件
//a为非激活状态,b为激活状态,1为显示,0为隐藏
var e = eve || window.event;
var code = e.keyCode || e.which;
//当按下↑时,改变索引
if (code == 38) {
if (index == 0) {
index = 0; //当index为0时,点击↑,index一直为0
} else {
index--;
}
for (var i = 0; i < oli.length; i++) {
oli[i].className = "";
}
//将通过↑选择的li的类名设置为“active”,并将li的内容显示在p中
oli[index].className = "active";
indexC = index;
op.innerHTML = oli[indexC].innerHTML;
}
index与indexC的关系前面说过了,这里就不再阐述。其他一些注释代码中有体现,code == 40与code==38的思路是一致的,就直接上代码
②下键
if (code == 40) {
if (index == oli.length - 1) {
index = oli.length - 1;
} else {
index++;
}
for (var i = 0; i < oli.length; i++) {
oli[i].className = "";
}
oli[index].className = "active";
indexC = index;
op.innerHTML = oli[index].innerHTML;
}
③回车键
//按下回车,ul消失,状态b赋为0;并将li的内容显示在p中
if (code == 13) {
//a为非激活状态,b为激活状态,0为隐藏,1为显示
if(a == 0 || b == 0){
oul.style.display = "block";
a = 1;
b = 1;
}else if(a == 1){
oul.style.display = "none";
b = 0;
}
op.innerHTML = oli[indexC].innerHTML;
indexC = index;
}
处于激活状态,回车键可以控制ul的显示隐藏,上下键可以控制li索引index的改变,同时改变indexC改变p标签中的显示。
以上就是我使用js模拟下拉框的实现。希望对大家有所帮助,有何不正确或者有更好的思路,希望可以告知。谢谢!