首页 > 代码库 > 下拉框插件开发 (二)

下拉框插件开发 (二)

今天有事出去了一趟,晚上加了下夜班,终于将它完成了,后续有bug,欢迎探讨。

附上:github地址  https://github.com/mapletao/downdrop

1,需求更新,完成自己想到的

对js里面的需求及每个方法要做的内容简述的描述了下并将其实现。

 技术分享

技术分享

技术分享

2.js编写

  1.立即执行函数,构造一个Downdrop函数,并注册该函数,同时进行安全处理,前面的;是为了执行出错的问题

;(function(){
    var Downdrop=function(opt){
        if(!(this instanceof Downdrop)){
            return new Downdrop(opt);    
        }
        this.init(opt);
    };
    window.Downdrop=Downdrop;
})();

  2.初始化函数

    初始化函数主要是做5件事

  1:扩展默认配置  setOpt

  2: 处理默认配置  dealOpt 

  3: 插入下拉框组件 setHtml 

  4: 设置事件 setFun

  5: 解除配置信息 removeOpt 

 3:扩展默认配置

  对参数进行处理,并扩展,设置默认参数

  

setOpt:function(opt){
            this.ulTemp=[‘<div class="downdrop">‘,
                                            ‘<div class="downdrop-header">请选择</div>‘,
                                            ‘<i class="angle"></i>‘,
                                            ‘<ul class="downdrop-con">‘,
                                            ‘</ul>‘,
                                        ‘</div>‘].join(‘‘);
            this.setting = {
                liTemp:‘<li data-val="{{val}}">{{text}}</li>‘,
                text:true,
                isHide:true,
            };
            mapletao.extend(this.setting,opt);
        },

4:处理默认配置

  处理列表项点击时该执行的事件,并将其保存在数组中,减少后面点击时的多重判断

  

dealOpt:function(){
            var self=this;
            self.dealLiFns=[];
            if(self.setting.text){
                self.dealLiFns.push(function(self){
                    self.headerDom.innerHTML = this.innerHTML;
                    self.headerDom.setAttribute("data-val",this.getAttribute("data-val"));
                });
            }
            if(self.setting.isHide){
                self.dealLiFns.push(function(self){
                    self.conDom.style.display = "none";
                });
            }
            if(self.setting.cb){
                self.dealLiFns.push(cb);
            }
        },

5:插入下拉框组件

  将下拉框html结构,并处理数据,并将数据插入到列表容器中,并保存将要用到的元素,后面就不需再去页面找了

  

setHtml:function(){
            var self = this;
            self.setting.ele.innerHTML=self.ulTemp;
            self.setEle();
            self.setList(self.setting.data);
        },
        setList:function(data){
            var self=this;
            self.lis=‘‘;
            data.forEach(function(obj){
                self.lis += self.formateString(self.setting.liTemp,obj);
            });
            self.conDom.innerHTML = self.lis;
            this.headerDom.innerHTML = "请选择";
        },
        formateString:function(str,data){
            return str.replace(/\{\{(\w+)\}\}/g,function(match,key){
                return typeof data[key] === undefined? ‘‘ : data[key];
            });
        },
        setEle:function(){
            var ele=this.setting.ele;
            this.headerDom=ele.getElementsByClassName("downdrop-header")[0];
            this.conDoms=document.getElementsByClassName("downdrop-con");
            this.conDom=ele.getElementsByClassName("downdrop-con")[0];
        },

6:事件设置

  主要对4个元素进行设置

  1:ele 下拉框插件容器 setEleClick 阻止冒泡,下拉框元素里面发生的事件不被外界获取,外界操作不影响里面的操作。

  2:下拉框头部 setHeaderClick   头部点击让列表显示,并将其它的隐藏

  3: 下拉列表容器 setConClick 代理模式,对下拉列表容器绑定点击事件,当列表项内容重新加载时正常使用,捕获li点击事件并处理

  4: document setDocClick 当点击其它地方时让所有下拉框列表内容的隐藏

setFun:function(){
            this.setEleClick();
            this.setHeaderClick();
            this.setConClick();
            this.setDocClick();
        },
        setEleClick:function(){
            var self=this;
            eventUtil.bindEvent(this.setting.ele,"click",self.setDomBubble);
        },
        setDomBubble:function(e){
            eventUtil.stopPropagation(e);
        },
        setHeaderClick:function(){
            var self=this;
            self.dealHeaderFn=self.bindFn(self.dealHeaderFn,self);
            eventUtil.bindEvent(this.headerDom,"click",self.dealHeaderFn);
        },
        dealHeaderFn:function(e,self){
            self.hideDom(e,self);
            self.conDom.style.display = "block";
        },
        setConClick:function(){
            var self=this;
            self.dealLiFn=self.bindFn(self.dealLiFn,self);
            eventUtil.bindEvent(this.conDom,"click",self.dealLiFn);
        },
        dealLiFn:function(e,self){
            e = eventUtil.getEvent(e);
            var target = eventUtil.getEventSrc(e);
            if(target.tagName.toLowerCase() === "li"){
                self.dealLiFns.forEach(function(obj){
                    obj.call(target,self);
                });
                target=null;
            }
        },
        bindFn:function(fn,args){
            return function(e){
                fn.call(this,e,args);
            };
        },
        hideDom:function(e,self){
            for(var i=0;i<self.conDoms.length;i++){
                self.conDoms[i].style.display = "none";
            }
        },
        setDocClick:function(){
            var self = this;
            Downdrop.prototype.hideDom=self.bindFn(self.hideDom,self);
            eventUtil.bindEvent(document,"click",self.hideDom);
        },

7:解除配置信息 

  删除一些以后不会用到的属性

removeOpt:function(){
            delete this.setting;
            delete this.lis;
            delete this.ulTemp;
        }

8:测试

  单元测试,改变参数,看看执行结果

  

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>下拉框</title>
    <link rel="stylesheet" type="text/css" href="css/reset.css" />
    <link rel="stylesheet" type="text/css" href="css/downdrop.css" />
</head>
<body>
    <p>默认</p>
    <div style="width:200px;margin-left: 20px;margin-top:10px;" id="J_test1">
    </div>
    <p>不赋值</p>
    <div style="width:200px;margin-left: 20px;margin-top:10px;" id="J_test2">
    </div>
    <p>不隐藏</p>
    <div style="width:200px;margin-left: 20px;margin-top:10px;" id="J_test3">
    </div>
    <p>不赋值,不隐藏</p>
    <div style="width:200px;margin-left: 20px;margin-top:10px;" id="J_test4">
    </div>
    <script src="js/common.js"></script>
    <script src="js/downdrop.js"></script>
    
    <script type="text/javascript">
        var data=[{
            "val":1,
            "text":"语文"
        },{
            "val":2,
            "text":"数学"
        },{
            "val":3,
            "text":"英语"
        },{
            "val":4,
            "text":"历史"
        },{
            "val":5,
            "text":"化学"
        },{
            "val":6,
            "text":"生物"
        },{
            "val":7,
            "text":"物理"
        }];
        var test1={
            ele:document.getElementById("J_test1"),
            data:data
        };
        var obj=new Downdrop(test1);
        var test2={
            ele:document.getElementById("J_test2"),
            data:data,
            text:false
        }
        var obj2=Downdrop(test2);
        var test3={
            ele:document.getElementById("J_test3"),
            data:data,
            isHide:false
        }
        var obj3=new Downdrop(test3);
        var test4={
            ele:document.getElementById("J_test4"),
            data:data,
            isHide:false,
            text:false
        };
        var obj4=new Downdrop(test4);
    </script>
</body>
</html>

9:测试结果

技术分享

技术分享

完成!

10:结语:

首先说说在这个组件开发中遇到的坑,参数传递,事件绑定中,作用域指向会偏离,指向当前点击的事件源,可能不是你自己想要的,这里用了下参与者模式,将我需要的用参数的形式传递,还用到了call,将this指向改成我想要的。还有对事件的封装,增强了自己的代码逻辑能力。有不足的地方,还请多多见谅。后面也会不时的进行bug处理,以及优化及扩张。

下拉框插件开发 (二)