AngularJS Dropdown指令相關(guān)的總結(jié)

Dropdown組件

自己封裝的一個(gè)簡(jiǎn)單的dropdown的組件

.ui-dropdown {
    position:relative;
    display:inline-block;
    *display:inline;
    *zoom:1;
    width:162px;
    border-radius:3px;
    text-align:left;
    font:12px/28px tahoma,arial,Hiragino Sans GB,WenQuanYi Micro Hei,'\5FAE\8F6F\96C5\9ED1','\5B8B\4F53',sans-serif;
    vertical-align:top
}
.ui-dropdown-bd {
    display:none;
    top:31px;
    left:0;
    min-width:calc(100% - 2px);
    max-height:346px;
    overflow-y:auto;
    overflow-x:hidden;
    _overflow:auto;
    position:absolute;
    padding-bottom:8px;
    background-color:#fff;
    border:1px solid #848484;
    border-radius:0 0 3px 3px;
    -webkit-box-shadow:0 0 0 2px #f7f7f7;
    box-shadow:0 0 0 2px #f7f7f7
}
.ui-dropdown-bd-right {
    left:auto;
    right:0
}
.ui-dropdown-bd .selected a,.ui-dropdown-bd .selected a:hover,.ui-dropdown-bd .selected a:active {
    background-color:#f10180;
    color:#fff
}
.ui-dropdown-bd a {
    display:block;
    padding:0 10px;
    text-overflow:ellipsis;
    white-space:nowrap;
    overflow:hidden;
    color:#333;
    text-decoration:none;
    *zoom:1
}
.ui-dropdown-bd a:hover {
    color:#666;
    text-decoration:none;
    background-color:#ededed
}
.ui-dropdown-bd a:active {
    background-color:#f10180;
    color:#fff
}
.ui-dropdown-hd {
    position:relative;
    z-index:2;
    padding:0 10px;
    border:1px solid #b3b3b3;
    border-radius:3px;
    background-color:#fff;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    cursor:pointer;
    *zoom:1
}
.ui-dropdown-hd:hover {
    border-color:#949494
}
.ui-dropdown-hd:hover .vipFont {
    color:#949494
}
.ui-dropdown-hd .vipFont {
    position:absolute;
    right:7px;
    color:#b3b3b3;
    -webkit-transition:-webkit-transform .2s;
    transition:transform .2s;
    line-height:1
}
.ui-dropdown-hd .i-arrow-down {
    top:7px
}
.ui-dropdown-hd .i-arrow-up {
    visibility:hidden;
    -webkit-transform:rotate(-180deg);
    -ms-transform:rotate(-180deg);
    transform:rotate(-180deg);
    top:6px
}
.ui-dropdown-current {
    display:block;
    zoom:1;
    color:#999;
    line-height:30px;
    text-decoration:none;
    font-size:14px;
    margin-right:10px;
    text-overflow:ellipsis;
    white-space:nowrap;
    overflow:hidden
}
.ui-dropdown-current:hover {
    color:#999;
    text-decoration:none
}
.ui-dropdown-tips {
    padding:12px 0 4px 10px;
    line-height:20px;
    color:#ed1616
}
.ui-dropdown .ui-dropdown-menu .ui-dropdown-loading {
    float:none;
    width:auto;
    padding-top:10px;
    line-height:80px;
    text-align:center;
    font-size:14px;
    color:#333
}
.ui-dropdown .ui-dropdown-menu .ui-dropdown-loading .ii-loading-pink-16x16,.ui-dropdown .ui-dropdown-menu .ui-dropdown-loading .ii-loading-pink-24x24,.ui-dropdown .ui-dropdown-menu .ui-dropdown-loading .ii-loading-pink-32x32 {
    vertical-align:middle;
    margin-right:12px
}
.ui-dropdown .ui-dropdown-menu .ui-dropdown-loading .text {
    display:inline-block;
    vertical-align:middle
}
.ui-dropdown-col-2,.ui-dropdown-col-3,.ui-dropdown-col-4 {
    width:115px
}
.z-ui-dropdown-open .ui-dropdown-col-2 .ui-dropdown-hd,.z-ui-dropdown-open .ui-dropdown-col-3 .ui-dropdown-hd,.z-ui-dropdown-open .ui-dropdown-col-4 .ui-dropdown-hd {
    border-bottom:0;
    padding-bottom:1px
}
.ui-dropdown-col-2 .ui-dropdown-bd,.ui-dropdown-col-3 .ui-dropdown-bd,.ui-dropdown-col-4 .ui-dropdown-bd {
    padding-top:8px
}
.ui-dropdown-col-2 .ui-dropdown-tips,.ui-dropdown-col-3 .ui-dropdown-tips,.ui-dropdown-col-4 .ui-dropdown-tips {
    padding-top:0
}
.ui-dropdown-col-2 .ui-dropdown-menu,.ui-dropdown-col-3 .ui-dropdown-menu,.ui-dropdown-col-4 .ui-dropdown-menu {
    padding:0 5px
}
.ui-dropdown-col-2 .ui-dropdown-menu li,.ui-dropdown-col-3 .ui-dropdown-menu li,.ui-dropdown-col-4 .ui-dropdown-menu li {
    float:left;
    _overflow:hidden
}
.ui-dropdown-col-2 .ui-dropdown-menu li a,.ui-dropdown-col-3 .ui-dropdown-menu li a,.ui-dropdown-col-4 .ui-dropdown-menu li a {
    _width:83px;
    padding:0 0 0 5px;
    margin:0 5px 2px
}
.ui-dropdown-col-2 .ui-dropdown-bd {
    width:190px
}
.ui-dropdown-col-2 .ui-dropdown-menu li {
    width:50%
}
.ui-dropdown-col-3 .ui-dropdown-bd {
    width:280px
}
.ui-dropdown-col-3 .ui-dropdown-menu li {
    width:33%
}
.ui-dropdown-col-4 .ui-dropdown-bd {
    width:370px
}
.ui-dropdown-col-4 .ui-dropdown-menu li {
    width:25%
}
.ui-dropdown-float {
    line-height:26px;
    width:120px
}
.ui-dropdown-float:hover,.ui-dropdown-float-hover {
    z-index:100
}
.ui-dropdown-float:hover .ui-dropdown-hd .vipFont,.ui-dropdown-float-hover .ui-dropdown-hd .vipFont {
    color:#848484;
    line-height:1
}
.ui-dropdown-float:hover .ui-dropdown-hd .i-arrow-up,.ui-dropdown-float-hover .ui-dropdown-hd .i-arrow-up {
    visibility:visible;
    -webkit-transform:rotate(0deg);
    -ms-transform:rotate(0deg);
    transform:rotate(0deg)
}
.ui-dropdown-float:hover .ui-dropdown-hd .i-arrow-down,.ui-dropdown-float-hover .ui-dropdown-hd .i-arrow-down {
    visibility:hidden;
    -webkit-transform:rotate(180deg);
    -ms-transform:rotate(180deg);
    transform:rotate(180deg)
}
.ui-dropdown-float:hover .ui-dropdown-bd,.ui-dropdown-float-hover .ui-dropdown-bd {
    display:block
}
.ui-dropdown-float:hover .ui-dropdown-current,.ui-dropdown-float-hover .ui-dropdown-current {
    color:#333
}
.ui-dropdown-float .ui-dropdown-current {
    display:inline-block;
    padding-right:16px;
    margin-right:0;
    color:#666;
    font-size:12px
}
.ui-dropdown-float .ui-dropdown-current:hover {
    color:#333
}
.ui-dropdown-float .ui-dropdown-hd {
    border:0 none;
    background:0
}
.ui-dropdown-float .ui-dropdown-hd .vipFont {
    right:auto;
    margin-left:-16px
}
.ui-dropdown-float .ui-dropdown-bd {
    top:0;
    max-height:312px;
    padding-top:30px;
    border-radius:0;
    border-color:#cbcaca
}
.ui-dropdown-float .ui-dropdown-bd a {
    color:#666
}
.ui-dropdown-float .ui-dropdown-bd a:hover,.ui-dropdown-float .ui-dropdown-bd a:active {
    background:0;
    color:#f10180
}
.ui-dropdown-float .ui-dropdown-bd .selected a,.ui-dropdown-float .ui-dropdown-bd .selected a:hover,.ui-dropdown-float .ui-dropdown-bd .selected a:active {
    background:0;
    color:#f10180
}
.ui-dropdown-float .ui-dropdown-menu .ui-dropdown-loading {
    line-height:50px;
    font-size:12px
}
.z-ui-dropdown-selected .ui-dropdown-current,.z-ui-dropdown-selected .ui-dropdown-current:hover {
    color:#333
}
.z-ui-dropdown-disable .ui-dropdown-hd {
    background-color:#f0efef;
    color:#999;
    cursor:not-allowed
}
.z-ui-dropdown-disable .ui-dropdown-hd:hover .vipFont {
    color:#b3b3b3
}
.z-ui-dropdown-disable .ui-dropdown-current,.z-ui-dropdown-disable .ui-dropdown-current:hover {
    color:#999;
    cursor:not-allowed
}
.z-ui-dropdown-open {
    z-index:100;
    -webkit-box-shadow:0 0 0 2px rgba(153,153,153,.08);
    box-shadow:0 0 0 2px rgba(153,153,153,.08)
}
.z-ui-dropdown-open .ui-dropdown-hd {
    border-radius:3px 3px 0 0;
    border-color:#848484;
    border-bottom-color:#dcdada
}
.z-ui-dropdown-open .ui-dropdown-hd .vipFont {
    color:#848484
}
.z-ui-dropdown-open .ui-dropdown-hd .i-arrow-up {
    visibility:visible;
    -webkit-transform:rotate(0deg);
    -ms-transform:rotate(0deg);
    transform:rotate(0deg)
}
.z-ui-dropdown-open .ui-dropdown-hd .i-arrow-down {
    visibility:hidden;
    -webkit-transform:rotate(180deg);
    -ms-transform:rotate(180deg);
    transform:rotate(180deg)
}
.z-ui-dropdown-open .ui-dropdown-bd {
    display:block
}
function BindDropdownEvent(elements, callback) {

    $('.ui-dropdown-hd', elements).unbind().click(function() {

        var element = $(this),
            uiDropdown = element.parent('.ui-dropdown');
        if (element.hasClass('z-ui-dropdown-disable')) {
            return false;
        }

        if (uiDropdown.hasClass('z-ui-dropdown-open')) {
            uiDropdown.removeClass('z-ui-dropdown-open');
        } else {
            $('.ui-dropdown').not(uiDropdown).removeClass('z-ui-dropdown-open');
            $('.multi-dropdown').not(uiDropdown).removeClass('z-ui-dropdown-open');
            uiDropdown.addClass('z-ui-dropdown-open');
            $(document).one('click', function() {
                uiDropdown.removeClass('z-ui-dropdown-open');
                return false;
            });
        }
        return false;
    });

    $('.ui-dropdown-bd', elements).unbind().each(function() {
        var element = $(this),
            uiDropdown = element.parent('.ui-dropdown'),
            liList = element.find('li'),
            uiDropdownCurrent = uiDropdown.find('.ui-dropdown-current');
        liList.click(function() {
            var subElement = $(this),
                item = subElement.find('a');
            liList.removeClass('selected');
            subElement.addClass('selected');

            var selectValue = item.attr('value');
            uiDropdownCurrent.attr('value', selectValue).text(item.text());
            uiDropdown.removeClass('z-ui-dropdown-open');
            $.isFunction(callback) && callback(item.text(), selectValue);

        });
    });
}

/**
     * Dropdown單選下拉框指令的實(shí)現(xiàn)
     * name : 區(qū)分不同的下拉框組件,字符串形式
     * ngModel : 單選下拉框綁定的值,默認(rèn)是選中項(xiàng)的key值
     * dataList : 下拉框下拉選項(xiàng)列表,數(shù)組形式,數(shù)組元素對(duì)象包含key 以及value。key作為向后臺(tái)交互的值,value作為前端控件顯示的值
     * empty : 布爾屬性值,當(dāng)賦值為true的時(shí)候,對(duì)下拉框組件進(jìn)行充值,下拉框中的值顯示的是placeholder的值"請(qǐng)選擇"
     * TODO : 多層級(jí)聯(lián)下拉框的實(shí)現(xiàn)方法      ------     當(dāng)下拉框列表接受點(diǎn)擊事件時(shí),廣播帶有組件name值為參數(shù)的selectUpdate的事件,用戶可以捕獲事件,根據(jù)時(shí)間的參數(shù)做出相應(yīng)的響應(yīng)。
     *        下拉框未選為空的狀態(tài)
     *        下拉框相應(yīng)雙向數(shù)據(jù)綁定的model,當(dāng)model變化時(shí),對(duì)應(yīng)的下拉框組件可以顯示對(duì)應(yīng)的選項(xiàng)
     */

    app.directive('dropdown',function(){
        return {
            restrict : 'EA',
            replace: true,
            template : '<div class="ui-form-item-group">'+
                            '<div class="ui-dropdown" ng-click="dropdown()">'+
                                '<div class="ui-dropdown-hd">'+
                                    '<a href="javascript:;" role="button" title="請(qǐng)選擇" class="ui-dropdown-current">請(qǐng)選擇</a> <i class="vipFont i-arrow-up"></i> <i class="vipFont i-arrow-down"></i>'+
                                '</div>'+
                                '<div class="ui-dropdown-bd">'+
                                    '<ul class="ui-dropdown-menu" >'+
                                        '<li ng-repeat="item in datalist" >'+
                                            '<a href="javascript:;" role="button" value="item.key" ng-click="select()">{{item.value}}</a>'+
                                        '</li>'+
                                    '</ul>'+
                                '</div>'+
                            '</div>'+
                        '</div>',
            scope :{
                name : '@',
                ngModel : "=",
                datalist : "=",
                empty : "="
            },
            link : function(scope,iElement,iAttrs){
                debugger
                var $elem = $(iElement);

                var dependents = scope.dependents ? scope.dependents.split(',') : false;
                var parentScope = scope.$parent;
                scope.name = scope.name || 'multi-select-' + Math.floor(Math.random() * 900000 + 100000);
                
                scope.$watch('empty',function(newValue, oldValue, scope){
                    debugger
                    if(newValue != oldValue){
                        if( newValue == true){
                            $elem.find('.ui-dropdown').removeClass("z-ui-dropdown-selected");
                            $elem.find(".ui-dropdown-current").text('請(qǐng)選擇');      
                        }

                         
                    }
                })
                
                scope.$watch('ngModel',function(newValue,oldValue,scope){
                    console.log('----------enter watch-------------');
                    debugger
                    if(newValue != oldValue){
                         scope.$root.$broadcast('selectUpdate', {
                                    // 將變動(dòng)的菜單的name屬性廣播出去,便于依賴于它的菜單進(jìn)行識(shí)別
                                    name: scope.name
                                });
                        for(var item in scope.datalist){
                            if(scope.datalist[item].key === newValue){
                                $elem.find(".ui-dropdown-current").text(scope.datalist[item].value);   
                                
                            }
                        }
                        
                    }
                })

                scope.dropdown = function(){
                    $elem.find('.ui-dropdown').toggleClass("z-ui-dropdown-open");

                }

                scope.select = function(){
                    // "z-ui-dropdown-selected"
                    debugger
                    $elem.find(".ui-dropdown").addClass("z-ui-dropdown-selected");
                    scope.empty = false;
                    scope.ngModel = scope.datalist[this.$index].key;
                    
                    // iAttrs["ngModel"] = "0"+this.$index;
//                    $elem.find(".ui-dropdown-current").text(scope.datalist[this.$index].value);
                    // scope.datafunc();
                   
                }
            }
        }
    })

在頁(yè)面中使用

 <label class="ui-label label-margin">標(biāo)記原因:</label>
                                                    <dropdown ng-model="formData.markReason" datalist="markReasons" name="markreasons-select"></dropdown>

級(jí)聯(lián)事件的響應(yīng)


 $scope.$on('selectUpdate',function(e,data){
            //TODO:
            debugger
            // console.log(data);
            if(data.name == "risktypes-select"){
                if($scope.formData.riskType == ''){
                    $scope.markReasons2 = [{key : '', value:"全部"}];
                    $scope.formData.markReason = '';
                    return ;
                }
                $scope.formData.markReason = '';
                util.ajax({
                    "url": "XXXX",
                    "type": "post",
                    $http: $http,
                    contentType: "application/x-www-form-urlencoded; charset=utf-8",
                    data: {
                        riskType: $scope.formData.riskType
                    },
                    success: function(res) {                
                        if (!res) {
                            return _showMessage("對(duì)不起您沒(méi)有權(quán)限", "信息錯(cuò)誤");
                        }else if(res.success == false) {
                            return _showMessage("用戶信息不匹配(未查到相關(guān)數(shù)據(jù)!)", "信息錯(cuò)誤")
                        }else {     
                            $scope.reasonListSeleted = res.results._defaultResult;
                            debugger
                                    $scope.markReasons2 = [{key : '', value:"全部"}];
                                for (var i = 0; i < $scope.reasonListSeleted.length; i++) {
                                    $scope.markReasons2.push({
                                        key : 
                                        $scope.reasonListSeleted[i].reasonId,
                                        value : 
                                        $scope.reasonListSeleted[i].reasonDesc
                                    });
                                }
                        };
                    }
                });
            }
        })

相關(guān)注意點(diǎn)

  • 指令綁定參數(shù)時(shí),最好不要是基本數(shù)據(jù)類型
    指令在進(jìn)行值綁定的時(shí)候,傳入的值最好是非基本類型。譬如綁定一個(gè)字符串類型riskTypengModel上,ngModel需要雙向數(shù)據(jù)綁定。
<dropdown ng-model="riskType" datalist="riskTypes">

這樣的綁定會(huì)出現(xiàn)一定的問(wèn)題
最好在controller中傳入的參數(shù)的對(duì)象的屬性,如下

<dropdown ng-model="obj.riskType" datalist="riskTypes">

在這個(gè)示例中datalist綁定的數(shù)據(jù)是數(shù)組類型,并非是簡(jiǎn)單數(shù)據(jù)類型,所以直接綁定即可。

擴(kuò)展

后期又對(duì)下拉框進(jìn)行優(yōu)化,支持disable,搜索篩選選項(xiàng)等功能。

    app.directive('searchdropdown',['$document','$filter','$timeout',function($document,$filter,$timeout){
        return {
            restrict : 'EA',
            replace: true,
            template : '<div class="ui-form-item-group">'+
                            '<div class="ui-dropdown" >'+
                                '<div class="ui-dropdown-hd">'+
                                    '<input placeholder="請(qǐng)選擇,輸入可篩選" class="ui-dropdown-search" ng-model="searchData" style="border: none;font: inherit;" ng-show="searchable && searching">'+
                                    '<a href="javascript:;" role="button" title="請(qǐng)選擇" class="ui-dropdown-current" ng-show="!(searchable && searching) "  ng-click="dropdown()">請(qǐng)選擇</a> <i class="vipFont i-arrow-up"  ng-click="dropdown()"></i> <i class="vipFont i-arrow-down"  ng-click="dropdown()"></i>'+
                                '</div>'+
                                '<div class="ui-dropdown-bd | filter:searchData">'+
                                    '<ul class="ui-dropdown-menu" >'+
                                        '<li ng-repeat="item in datalist | filter:{text:searchData}" >'+
                                            '<a href="javascript:;" role="button" value="item.value" ng-click="select($event)">{{item.text}}</a>'+
                                        '</li>'+
                                    '</ul>'+
                                '</div>'+
                            '</div>'+
                        '</div>',
            scope :{
                ngModel : "=",
                datalist : "=",
                disabled : "=",
                searchable : "="
            },
            controller : function($scope){
                $scope.name = $scope.name || 'dropdown-' + Math.floor(Math.random() * 900000 + 100000);
                $scope.searching = false;
                $scope.myComparator = function (expected, actual) {
                    return angular.equals(expected.toLowerCase(), actual.toLowerCase());
                }
            },
            link : function(scope,iElement,iAttrs){
                
                var $elem = $(iElement);
               
                for(var item in scope.datalist){
                    if(scope.datalist[item].value === scope.ngModel){
                        $elem.find(".ui-dropdown-current").text(scope.datalist[item].text);   
                        $elem.find(".ui-dropdown").addClass("z-ui-dropdown-selected");
                    }
                }
                if(scope.disabled == true){
                    $elem.find(".ui-dropdown").addClass("z-ui-dropdown-disable");
                }

                $elem.find('.ui-dropdown-search').bind('focus',function(event){
                    
                    console.log('ui-dropdown-search is on focus');
                    $elem.find('.ui-dropdown').addClass("z-ui-dropdown-open");
                    event.stopPropagation();
                })

                // $elem.find(".ui-dropdown-hd").bind('blur',function(){
                //     alert('blur');
                // })

                // $elem.find('.ui-dropdown-search').bind('blur',function(event){
                    
                //     console.log('ui-dropdown-search is on blur');
                //     scope.$apply(function(){
                //         scope.searching = false;      
                //     })
                // })
                
                scope.dropdown = function(){
                    console.log("ui-dropdown trigger dropdown event");
                    if(scope.disabled)
                        return ;
                    $elem.find('.ui-dropdown').toggleClass("z-ui-dropdown-open");
                    if($elem.find('.ui-dropdown').hasClass("z-ui-dropdown-open")){
                        console.log("---------" + scope.name +"------bind $document event -----------");
                        // 對(duì)于這種問(wèn)題,jQuery的解決方案是使用事件綁定的命名空間。即在事件名稱后添加 .something 來(lái)區(qū)分自己這部分行為邏輯范圍。  
                        $(document).bind("click."+scope.name, function(event) {
                            console.log("-------go into $document click"+scope.name+"-------");
                            var judge = $(event.target).closest($elem).length > 0;
                            // if(!$elem.find('.ui-dropdown').hasClass("z-ui-dropdown-open")){
                            //     console.log("---------" + scope.name +"------unbind $document event -----------");
                            //     $(document).unbind("click."+scope.name);
                            // }
                            if(!judge){
                                if(scope.searchable && scope.searching)  {
                                    scope.$apply(function(){
                                        scope.searching = false;   
                                    })
                                }
                                $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-open");   
                                $(document).unbind("click."+scope.name);
                            }
                        });
                    }else{
                         console.log("---------" + scope.name +"------unbind $document event -----------");
                        $(document).unbind("click."+scope.name);
                    }
                    if(scope.searchable){
                        scope.searching = !scope.searching;
                        // if(scope.searching){
                            scope.searchData = scope.ngModel;
                            var timer = $timeout(
                                function() {
                                    $elem.find('.ui-dropdown-search').focus();
                                    console.log( "Timeout executed", Date.now() );
                            },100);

                            scope.$on("$destroy",function( event ) {

                                $timeout.cancel( timer );
                            });
                        // }
                    }
                }

                scope.select = function($event){
                    
                    $elem.find(".ui-dropdown").addClass("z-ui-dropdown-selected");
                    var temp = $filter('filter')(scope.datalist,scope.searchData);
                    console.log(temp);
                    scope.ngModel = temp[this.$index].value;
                    $elem.find(".ui-dropdown-current").text(temp[this.$index].text)
                    $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-open");  
                    scope.searching = false;
                    console.log(scope.searching);
                }
                
                scope.$watch('ngModel',function(newValue,oldValue,scope){
                     var isHitted = false;
                    if(newValue != oldValue){
                        for(var item in scope.datalist){
                            if(scope.datalist[item].value === newValue){
                                $elem.find(".ui-dropdown-current").text(scope.datalist[item].text);   
                                $elem.find(".ui-dropdown").addClass("z-ui-dropdown-selected");
                                isHitted = true;
                            }
                        }
                        if(!isHitted){
                            $elem.find(".ui-dropdown-current").text('請(qǐng)選擇');   
                            $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-selected");
                        }
                    }
                })

                // $(document).bind("click."+scope.name, function(event) {
                //             console.log("-------go into $document click-------");
                //             var judge = $(event.target).closest($elem).length > 0;
                //             if(!judge){
                //                 if(scope.searchable && scope.searching)  {
                //                     scope.$apply(function(){
                //                         scope.searching = false;   
                //                     })
                //                 }
                //                 $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-open");   
                //             }
                //         });


                // $document.bind("click", function(event) {
                //     var judge = $(event.target).closest($elem).length > 0;
                //     if(!judge){
                //         if(scope.searchable && scope.searching)  {
                //             // $elem.find('.ui-dropdown-search').blur();
                //             // console.log('manually trigger blur');
                //             scope.$apply(function(){
                //                 scope.searching = false;   
                //             })
                //         }
                //         $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-open");   
                //     }
                // });

                // $(document).one("click", function(event) {
                //     var judge = $(event.target).closest($elem).length > 0;
                //     if(!judge){
                //         if(scope.searchable && scope.searching)  {
                //             // $elem.find('.ui-dropdown-search').blur();
                //             // console.log('manually trigger blur');
                //             scope.$apply(function(){
                //                 scope.searching = false;   
                //             })
                //         }
                //         $elem.find(".ui-dropdown").removeClass("z-ui-dropdown-open");   
                //     }
                // });

            }
        }
    }]) 
simple-select.gif
search-select.gif
disbaled.png

AngularJS中實(shí)現(xiàn)無(wú)限級(jí)聯(lián)動(dòng)菜單

AngularJS中實(shí)現(xiàn)無(wú)限級(jí)聯(lián)動(dòng)菜單

directive('multiLevelSelect', ['$parse', '$timeout', function ($parse, $timeout) {
 
    // 利用閉包,保存父級(jí)scope中的所有多級(jí)聯(lián)動(dòng)菜單,便于取值
    var selects = {};
 
    return {
 
        restrict: 'CA',
 
        scope: {
            // 用于依賴聲明時(shí)指定父級(jí)標(biāo)簽
            name: '@name',
 
            // 依賴數(shù)組,逗號(hào)分割
            dependents: '@dependents',
 
            // 提供具體option值的函數(shù),在父級(jí)change時(shí)被調(diào)用,允許同步/異步的返回結(jié)果
            // 無(wú)論同步還是異步,數(shù)據(jù)應(yīng)該是[{text: 'text', value: 'value'},]的結(jié)構(gòu)
            source: '=source',
 
            // 是否支持控制選項(xiàng),如果是,空值的標(biāo)簽是什么
            empty: '@empty',
 
            // 用于parse解析獲取model值(而非viewValue值)
            modelName: '@ngModel'
        },
 
        template: ''
            // 使用ng-show而非ng-if,原因上文已經(jīng)提到
            + '<option ng-show="empty" value="">{{empty}}</option>'
            // 使用樸素的ng-repeat
            + '<option ng-repeat="item in items" value="{{item.value}}">{{item.text}}</option>',
 
        require: 'ngModel',
 
        link: function (scope, elem, attr, model) {
 
            var dependents = scope.dependents ? scope.dependents.split(',') : false;
            var parentScope = scope.$parent;
            scope.name = scope.name || 'multi-select-' + Math.floor(Math.random() * 900000 + 100000);
 
            // 將當(dāng)前菜單的getValue函數(shù)封裝起來(lái),放在閉包中的selects對(duì)象中方便調(diào)用
            selects[scope.name] = {
                getValue: function () {
                    return $parse(scope.modelName)(parentScope);
                }
            };
 
            // 保存初始值,原因上文已經(jīng)提到
            var initValue = selects[scope.name].getValue();
 
            var inited = !initValue;
            model.$setViewValue('');
 
            // 父級(jí)標(biāo)簽變化時(shí)被調(diào)用的回調(diào)函數(shù)
            function onParentChange() {
                var values = {};
                // 獲取所有依賴的菜單的當(dāng)前值
                if (dependents) {
                    $.each(dependents, function (index, dependent) {
                        values[dependent] = selects[dependent].getValue();
                    });
                }
 
                // 利用閉包判斷io造成的異步過(guò)期
                (function (thenValues) {
 
                    // 調(diào)用source函數(shù),取新的option數(shù)據(jù)
                    var returned = scope.source ? scope.source(values) : false;
 
                    // 利用多層閉包,將同步結(jié)果包裝為有then方法的對(duì)象
                    !returned || (returned = returned.then ? returned : {
                        then: (function (data) {
                            return function (callback) {
                                callback.call(window, data);
                            };
                        })(returned)
                    }).then(function (items) {
 
                        // 防止由異步造成的過(guò)期
                        for (var name in thenValues) {
                            if (thenValues[name] !== selects[name].getValue()) {
                                return;
                            }
                        }
 
                        scope.items = items;
 
                        $timeout(function () {
 
                            // 防止由同步(嚴(yán)格的說(shuō)也是異步,注意事件隊(duì)列)造成的過(guò)期
                            if (scope.items !== items) return;
 
                            // 如果有空值,選擇空值,否則選擇第一個(gè)選項(xiàng)
                            if (scope.empty) {
                                model.$setViewValue('');
                            } else {
                                model.$setViewValue(scope.items[0].value);
                            }
 
                            // 判斷恢復(fù)初始值的條件是否成熟
                            var initValueIncluded = !inited && (function () {
                                for (var i = 0; i < scope.items.length; i++) {
                                    if (scope.items[i].value === initValue) {
                                        return true;
                                    }
                                }
                                return false;
                            })();
 
                            // 恢復(fù)初始值
                            if (initValueIncluded) {
                                inited = true;
                                model.$setViewValue(initValue);
                            }
 
                            model.$render();
 
                        });
                    });
 
                })(values);
 
                 
            }
 
            // 是否有依賴,如果沒(méi)有,直接觸發(fā)onParentChange以還原初始值
            !dependents ? onParentChange() : scope.$on('selectUpdate', function (e, data) {
                if ($.inArray(data.name, dependents) >= 0) {
                    onParentChange();
                }
            });
 
            // 對(duì)當(dāng)前值進(jìn)行監(jiān)聽(tīng),發(fā)生變化時(shí)對(duì)其進(jìn)行廣播
            parentScope.$watch(scope.modelName, function (newValue, oldValue) {
                if (newValue || '' !== oldValue || '') {
                    scope.$root.$broadcast('selectUpdate', {
                        // 將變動(dòng)的菜單的name屬性廣播出去,便于依賴于它的菜單進(jìn)行識(shí)別
                        name: scope.name
                    });
                }
            });
 
        }
    };
}]);

angularJS中組件復(fù)用和封裝

https://www.zybuluo.com/lxjwlt/note/331587

http://www.jb51.net/article/58229.htm

http://www.tuicool.com/articles/QfyMna

http://www.tuicool.com/articles/fqiI73M

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容