天天看点

Js模拟下拉框(select-option)的实现

js模拟下拉框

今天想给大家分享一下之前自己做的一个js模拟下拉框,所有select-option中我能发现的操作,都在我的代码中将其实现,希望对大家有所帮助。如果select中还有一些本人未实现的希望大家在评论区指出。话不多说,直入主题。

  1. 首先是布局,很多时候布局也会对js的实现造成影响,所以布局一定要写好
div id = "box">
	<p></p>
	<ul>
	    <li class = "active">寒冰射手 艾希</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>
           

浏览器显示结果如下:

Js模拟下拉框(select-option)的实现
Js模拟下拉框(select-option)的实现

p标签里默认存放的是下拉框中的第一条,默认ul>li是不显示的。

布局就说到这里,本来不想多说关于布局,但是还是放出来希望对大家有所帮助。

  1. 然后我们开始说js部分的实现,我会将其分成一个个部分来阐述如何实现。

(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模拟下拉框的实现。希望对大家有所帮助,有何不正确或者有更好的思路,希望可以告知。谢谢!