jquery 无限级 Cascader 级联选择器 插件

本文由清尘发表于2018-07-01 18:59最后修改于2019-05-07属于jQuery分类

点击查看演示

仿element ui的cascader效果自己写的一个jquery版级联选择器

使用:

            //默认初始化传递数据
            $('#cascaderbox').cascader({data:lists}); 
            //
            $('#cascaderbox2').cascader({
                data:lists2,
                changeOnSelect:true, //开启选择任意级
                selectFn:function(selectjson){ //selectFn回调函数
                    console.log('对外提供接口')
                    console.log(JSON.stringify(selectjson)); //参数为最终选择的json数组
                    $('#testJSON').html(JSON.stringify(selectjson));
                    }
                });
            
    <div class="cascaderbox" id="cascaderbox">
        <div class="inputbox">
            <span class="arrdown"></span>
            <input autocomplete="off" class="searchtxt" type="text" placeholder="搜索或点击下拉选择">
            <span class="labelshow"></span>
        </div>
        <div class="dlist hid"> </div>
        <div class="dlist searchdlist hid"></div>
    </div>

.cascaderbox .hid{visibility: hidden;}
.cascaderbox{width: 320px; height: 42px; line-height: 40px; position: relative;}
.cascaderbox .inputbox{width: 100%; height: 42px; border:1px solid #e4e7ed; border-radius: 8px; cursor: pointer; position: relative;}
.cascaderbox .searchtxt{display: inline-block; box-sizing: border-box; width: 85%; height: 40px; line-height: 40px; margin-left: 5%; border:0 none; overflow: hidden; text-overflow: ellipsis; color: #606266;}
.cascaderbox .arrdown{float: right; display: inline; width: 12px; height: 12px; background: url('img/ld_dot.png') left top no-repeat; margin-right: 10px; margin-top: 15px;}
.cascaderbox.open .arrdown{transform: rotate(180deg);}
.cascaderbox .dlist{position: absolute;left: 0;top: 48px; white-space: nowrap; background-color: #fff; border:1px solid #e4e7ed; height: 300px; overflow: hidden; z-index: 999;}
.cascaderbox .dlist_ul{min-width: 160px; display: inline-block; border-right: 1px solid #e4e7ed;  padding:0 10px; height: 300px; overflow: auto;}
.cascaderbox .dlist_ul:last-child{border-right: 0 none;}
.cascaderbox .item,.cascaderbox .item2{padding:5px 10px; background: url('img/ld_dr.png') right 18px no-repeat; max-width: 250px;overflow:hidden; text-overflow: ellipsis; cursor: pointer;}
.cascaderbox .dlist_search .item2{background: none; max-width: 350px;}
.cascaderbox .item:hover,.cascaderbox .item.on{color: #409EFF;}
.cascaderbox .item.lastchild{background: 0 none;}
.cascaderbox .labelshow{position: absolute; left: 20px; top:0px; width: 90%; display: inline-block; height: 42px; color: #606266; overflow: hidden; text-overflow: ellipsis;}
.cascaderbox .searchdlist,.cascaderbox .searchdlist .dlist_ul{height: auto;max-height: 300px;}
.cascaderbox .labelshow.hid{display: none;}
.cascaderbox .nosearch{color: #c0c4cc; height: 30px;;}

js代码:

(function($){
    $.fn.cascader = function(options){
        var defaults = {
            data:[],
            changeOnSelect:false,
            selectFn:function(selectjson){}
        };
        var opts = $.extend(defaults,options);
      
        var _this = this,searchtxt = _this.find('.searchtxt'),dlist = _this.find('.dlist').eq(0),searchdlist = _this.find('.searchdlist'),curArr = [],labelshow = _this.find('.labelshow'),level = 0,initData = false,selJson=[],searchArr = [],searActiveArr = [],searchArr_value=[],focusState=false;

        labelshow.bind('click',function(){
            if(!focusState){
                searchtxt.trigger('focus');
                focusState = true;
            }
            
        })

        searchtxt.bind('focus',function(){
            if(!initData){
                createUl(opts.data);
                popOpen(dlist);
                createSearchArr(opts.data);
                initData = true;
            }else if(searchdlist.hasClass('hid')){
                popOpen(dlist);
            }
            
        }).bind('blur',function(){
            focusState = false;
        }).bind('keyup',function(){
            var serchstr = $(this).val();
            popClose();
            labelshow.addClass('hid');
            if(serchstr.length > 0){
                createSearchBox(serchstr);
            }else{
                popClose();
            }
        })

        dlist.delegate('li.item','click',function(){
           var parent_index = $(this).parent().index();
           var value = $(this).attr('data-value');
           $(this).addClass('on').siblings().removeClass('on');
           level = parent_index;
           getArray(opts.data,value);
        });

        searchdlist.delegate('li.item2','click',function(){
            var searStr = ($(this).text()).split('/'),litxt = dlist.find('.dlist_ul').eq(0),len = searStr.length;

            litxt.nextAll().remove();

            createSearchdlist(opts.data,searStr[0]);

            for(var i = 1; i<len-1; i++){
                createSearchdlist(searActiveArr,searStr[i]);
            }
            dlist.find('.dlist_ul').each(function(i){
                var jqElArr = $(this).find('li');
                highlighting(jqElArr,searStr[i])
                if(i == len-1){
                    getValue();
                    labelshow.removeClass('hid');
                    searchtxt.val('');
                    popClose();
                }
            })

        })

        function highlighting(jqElArr,highStr){
            jqElArr.each(function(){
                var curtxt = $(this).attr('data-label');
                if(highStr == curtxt){
                    var selectedItem = $(this);
                    $(this).addClass('on').siblings().removeClass('on');
                    scrollToOpened(selectedItem);
                }
            })
            
        }

        function scrollToOpened(selectedItem){
          var listUl = selectedItem.parents('ul');
            if(selectedItem.size()>0){
                var scrollTop = listUl.scrollTop(),top = selectedItem.position().top + scrollTop;
                if(scrollTop < top){
                    top = top -(listUl.height() - selectedItem.height())/2;
                    listUl.scrollTop(top);
                }
            }
        }

        function createSearchdlist(data,label){
            for(var i in data){
                if(data[i].label == label){
                    searActiveArr = data[i].children;
                }
            }
            createUl(searActiveArr);
           
        }

        var htmlClickHandler =function(e){
            if(dlist.hasClass('hid') && searchdlist.hasClass('hid')) return;
            var cascader = $(e.target).parents('.cascaderbox');
            if(cascader.size() == 0){
                popClose();
                if(labelshow.hasClass('hid')){
                    labelshow.removeClass('hid')
                    searchtxt.val('');
                }
            };


        }

        function getArray(data,value){
            for(var i in data){
                if(data[i].value == value){
                    curArr = data[i].children;
                    createEl();
                    break;
                }else{
                    getArray(data[i].children,value);
                }
            }
        }

        function createEl(){
            if(curArr){
               /*  点击非最后一个子级 */
                _this.find('.dlist_ul').eq(level).nextAll().remove();
                createUl(curArr);
                popOpen(dlist); 
                if(opts.changeOnSelect){ /* 选择即改变,可选择任意级 */
                     getValue(); 
                }
                
            }else{
                /* 点击最后一个子级 */
                _this.find('.dlist_ul').eq(level).nextAll().remove();
                getValue(); 
                popClose();
            }
        }

        function createUl(data){
            var arr = data, liArr = []; ul = $('<ul class="dlist_ul"></ul>');
            $.each(arr,function(i,data){
                var lastClass = '';
                if(!data.children){
                    lastClass = 'lastchild'
                }
                liArr.push('<li data-label="'+data.label+'" data-value="'+data.value+'" class="item '+lastClass+'">'+data.label+'</li>')

            })
            ul.append(liArr.join(''));
            dlist.append(ul);
           
        }

        function getValue(){
            selJson = []; /* 最终选项数组 */
            dlist.find('li.on').each(function(i,data){
                var label = $(this).attr('data-label'),
                    value = $(this).attr('data-value');
                selJson.push({"value":value,"label":label});

            })

            var selectedStr = selJsonToStr(selJson);

            searchtxt.attr('placeholder','');
            labelshow.html(selectedStr);
            opts.selectFn(selJson);
            
        }

        function selJsonToStr(arr){
            var listArr = [];
            $.each(arr,function(i,data){
                var label = data.label;
                listArr.push(label);
            })
            str = listArr.join(' / ');
            return str;
        }

        function createSearchArr(data,label){
            for(var i in data){
                if(!label){
                    label = ''
                }
                var str = label + '' + data[i].label + "/";
                if(data[i].children){
                    curArr = data[i].children;
                    createSearchArr(curArr,str)
                }else{
                    str = str.substring(0,str.lastIndexOf("/"));
                    searchArr.push(str);
                    searchArr_value.push(data[i].value);
                }
            }
        }

        function createSearchBox(label){
            var liArr = []; ul = $('<ul class="dlist_ul dlist_search"></ul>'); 
            $.each(searchArr,function(i,data){
                if(data.indexOf(label) != -1){
                    var value = searchArr_value[i];
                    liArr.push('<li data-value="'+value+'" class="item2">'+data+'</li>')
                }
            });
            
            if(liArr.length != 0){
                searchdlist.empty();
                ul.append(liArr.join(''));
                searchdlist.append(ul);
                popOpen(searchdlist);
            }else{
                searchdlist.empty();
                ul.append('<li class="nosearch">无匹配数据</li>')
                searchdlist.append(ul);
                popOpen(searchdlist);
            }
        }


     
        function popClose(){
            _this.removeClass('open');
            _this.find('.dlist').addClass('hid');
        }

        function popOpen(el){
            _this.addClass('open');
            el.removeClass('hid');
        }

        $('html').bind('click',htmlClickHandler)


        
    }
})(jQuery)