下拉树列表菜单选择器

虽然网上有许多的实现下拉树列表菜单的实现,但都是基于某一框架的,感觉使用起来过于复杂。

为了巩固学习的JS知识,于是尝试着自己写一个。


这个下拉树列表整体放置在一个div中。为了使其看起来和HTML自带的下拉列表类似,我选择了使用select标签,但一开始并不在其中嵌套option选项。(其实也可以用input自己实现一个,只不过我觉得这样用方便也美观......)

在select标签之后跟着一个div,主要用来放置目录列表,目录用ul标签嵌套的方式实现。该div使用绝对定位(这样在div显示的时候就不会占用文档空间),并且初始出于隐藏状态。

通过给select标签添加click事件监听,使目录div显示。

在选择目录后,生成一个option选项,将其加入到select中并将其选中,但option还是要隐藏,就可以在select中设置值了。(因为好像select不能直接通过给value赋值的方法赋值,所以只能采用这个折中的办法了。如果是用的input实现的,那么直接对其value赋值,就没这么麻烦。)


目前我只是完成一个粗略的结构,树形结构的展开和收缩功能也还没有加上,先写下这些东西记录下学习成果。随后逐步完善。

下面是代码

<!DOCTYPE html>
<html>
    <head>
        <title>Test2</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <div>TODO write content</div>
        <!-- 下来树列表 -->
        <div style="width:200px;">
            <select style="width:200px;padding: 0;margin: 0;" οnclick="createTree(this)"></select>
            <div  style="width:200px;padding-top:2px;margin: 0;background-color: #ccccff;display: none;overflow: auto;position: absolute;">
                <ul>
                    <li><a href="javascript:void(0);" title="A">A</a>
                        <ul>
                            <li><a href="javascript:void(0);" title="A1">A1</a></li>
                            <li><a href="javascript:void(0);" title="A2">A2</a>
                                <ul>
                                    <li><a href="javascript:void(0);" title="AA2">AA2</a></li>
                                    <li><a href="javascript:void(0);" title="AA3">AA3</a></li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                    <li><a href="javascript:void(0);" title="B">B</a>
                        <ul>
                            <li><a href="javascript:void(0);" title="B1">B1</a></li>
                            <li><a href="javascript:void(0);" title="B2">B2</a></li>
                        </ul>
                    </li>
                    <li><a href="javascript:void(0);" title="C">C</a></li>
                </ul>
            </div>
        </div>
    <script>
        function createTree(component){
            
            //为select定义一个blur属性,用于标记select是否失去焦点
            //这个属性将在select失去焦点时隐藏目录div是用到
            //因为不能简单的设置当select失去焦点时就隐藏目录div
            //这样的话点击目录时就会发生冲突,导致目录提前隐藏而没有选中值
            component.blur = false;
            component.addEventListener("blur",function(){
                this.blur = true;
            });
            
            
            //获得目录列表,其中每两个标签之间有一个文本节点,所以select的父节点有5个子节点
            //而包含列表的div是第四个节点
            var parent = component.parentNode;
            var treeMenu = parent.getElementsByTagName("div")[0];
            
            console.log("select is clicked "+component.blur);
            
            
            //点击select时,列表是展开的就收缩列表,否则就展开列表
            if(treeMenu.style.display === "none"){
                treeMenu.style.display = "";
                console.log("display");
            }
            else{
                treeMenu.style.display = "none";
                console.log("select hidden");
            }
            
            
            //获得每一个目录的link,并且给每一个link都绑定一个事件
            //当该目录被选中时,就给select插入一个option,并且选中该option
            //并且将该option设置为隐藏的,这样就设置了select的值
            var menuLinks = treeMenu.getElementsByTagName("a");
            //console.log(menuLinks[0].innerHTML);
            for(var i=0;i<menuLinks.length;i++){
                //console.log(menuLinks[i].innerHTML);
               menuLinks[i].addEventListener("click",function(){
                   console.log("Link is clicked");
                    var text = this.innerHTML;
                    var option = document.createElement("option");
                    option.text = text;
                    option.selected = true;
                    option.style.display = "none";
                    component.add(option,null);
                    treeMenu.style.display = "none";
                    console.log("link hidden");
                });
            }
            
            //给body绑定一个点击事件,这个事件用于检测鼠标是否在下拉树列表外进行了点击
            //如果是,则要隐藏下拉树,相当于下拉树列表失去了焦点
            //判断的方法是根据发生点击事件是鼠标的位置
            document.body.addEventListener("click",function(event){
                console.log("body is clicked");
                    if(treeMenu.style.display !== "none"){
                        /*console.log("top: "+treeMenu.offsetTop+" left: "+treeMenu.offsetLeft+
                                " height: "+treeMenu.offsetHeight+" width: "+treeMenu.offsetWidth);
                        console.log("eventX: "+event.clientX+" eventY: "+event.clientY);
                        console.log(event.type);*/
                        if((event.clientX<treeMenu.offsetLeft ||
                           event.clientX>(treeMenu.offsetLeft+treeMenu.offsetWidth) ||
                           event.clientY<treeMenu.offsetTop ||
                           event.clientY>(treeMenu.offsetTop+treeMenu.offsetHeight))
                           && component.blur){
                           treeMenu.style.display = "none";
                           console.log("body hidden");
                        }
                    }
            });
            
            //给window绑定事件隐藏目录
            //因为body并不一定能覆盖完整个浏览器窗口
            //检测点击是否发生在body之外,如果是,就应该隐藏目录
            //依然要检测select的blur属性,不然会有一个小bug
            //在select边缘点击的时候,如果不检测select blur属性,会触发目录隐藏
            window.addEventListener("click",function(event){
               console.log("window is clicked"); 
               //console.log(event.clientY);
               if((event.clientX<document.body.offsetLeft ||
                       event.clientX>(document.body.offsetLeft+document.body.offsetWidth) ||
                       event.clientY<document.body.offsetTop ||
                       event.clientY>(document.body.offsetTop+document.body.offsetHeight))
                       && component.blur)
                   if(treeMenu.style.display !== "none"){
                       treeMenu.style.display = "none";
                       console.log("widow hidden");
                   }
            });
        }
    </script>
    </body>
</html>


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值