JS列表的下拉菜單組件(仿美化控件select)


     今天是農歷23 也是小年,在這祝福大家新年快樂!今天給大家分享的是:JS列表的下拉菜單組件,因為目前項目正好要用到這個,所以提前研究了下,看到KISSY也有這么一個組件,所以自己也封裝了一個,KISSY demo鏈接

     KISSY組件名字叫 "一個解決大數據列表渲染效率的下拉菜單組件。", 他對這個組件做了一次小優化。(假如服務器返回10000條數據或者更多的話,那么我們前端一次性操作10000條數據的話很會影響性能,他們做的優化是:將數組拆分,根據瀏覽器本身的腳本執行能力進行分批渲染。),但是目前kissy demo上有加載2000條數據的demo,在火狐下還是會有卡住的現象,如果稍不好的話 有可能會導致瀏覽器重啟的可能。而我今天做的demo和他們的功能類似,但是唯一不同點就是:假如返回10000條數據的話 我沒有對數組分批渲染,而是循環10000次 把數據保存到一個變量里 然后一次性動態加載進來,或許這么做和他們那種操作效率可能會低那么點(具體的我沒有測試過)。所以我今天的標題沒有和他們那樣一起叫。所以今天的標題上:"JS列表的下拉菜單組件". 首先要說明的是:一般的需求肯定是滿足的,一個下拉框也不可能有那么多數據(一般情況下!)。

下面是我做的demo(JS列表的下拉菜單組件)。JSFiddle地址如下:

 想要看demo,請輕輕的點擊我!我怕疼的!溫柔點!

 基本原理:

      滿足的基本功能是:一個基本下拉框,但是他與下拉框不同的是:他既可以輸入精確匹配到某一項,也可以點擊下拉,也支持鍵盤上下移操作。但同時當我在輸入框輸入時候沒有匹配到某一項時候,點擊文檔document 那么下拉框隱藏掉,input值為空。同時且支持靜態數據渲染 又支持post請求渲染數據。

基本的配置項如下:

  parentCls
'.parentCls',   輸入框父元素class 默認
inputElemCls  '.inputElem',     目標元素的class
inputWidth  100,               目標元素的寬度 單位(PX)
 selectCls   '.caret',            下來小箭頭class
hoverBg 'hoverBg',          鼠標移上去的背景
isSelectHide true,                  點擊下拉框某一項 是否隱藏 默認true
timeId 100,                  默認多少毫秒消失下拉框
dataSource [],                    數據源返回的格式如下:靜態數據 否則的話   (如果數組為空的話) 在內部發post請求
renderHTMLCallback  null               keyup時 渲染數據后的回調函數
callback  null                點擊某一項 提供回調

 如上面配置: 其中dataSource如果初始化為空數組的話,那么直接在內部發post請求渲染數據,否則的話 也可以渲染靜態數據:如下

dataSource: [
            {text: "列表項1", value: 1},
            {text: "列表項2", value: 2},
            {text: "列表項3", value: 3},
            {text: "列表項4", value: 4},
            {text: "列表項5", value: 5},
            {text: "列表項6", value: 6},
            {text: "列表項7", value: 7},
            {text: "列表項8", value: 8},
            {text: "列表項9", value: 9},
            {text: "列表項10", value: 10},
            {text: "列表項11", value: 11}
        ]

 如果dataSource 的長度大於0 的話 那么他會按照靜態數據渲染,不會發post請求 否則的話 (如果數組為空,支持發post請求) 去渲染數據。

對外提供的方法有:

setValue() 

 在外部實例話后 可以調用此方法 設置初始化值。比如demo頁面設置的格式如下:
        // 設置初始化選擇項。
        selectedItem: {
            value: "4",
            text: "列表項4"
        }

 getValue();   獲取輸入框的值。

代碼簡單的分析下:

首先初始化init方法:代碼如下:

init: function(options) {
        this.config = $.extend(this.config, options || {});
        var self = this,
            _config = self.config,
            _cache = self.cache;
        $('.drop-trigger').css({"left":_config.inputWidth - 20 + 'px'});
        /* 
         * 鼠標點擊輸入框時 渲染數據
         */
        $(_config.inputElemCls).each(function(index,item){
            
            // 對input定義寬度 其父節點div也是根據input寬度定義的。
            $(item).css({'width':_config.inputWidth});
            var tagParent = $(item).closest(_config.parentCls);
            $(tagParent).css({'width':_config.inputWidth});

            $(item).bind('keyup',function(e){
                e.preventDefault();
                var targetVal = $.trim($(this).val()),
                    keyCode = e.keyCode,
                    elemHeight = $(this).outerHeight();
                
                var targetParent = $(this).closest(_config.parentCls);
                $(targetParent).css({'position':'relative'});
                
                // 刪除標識
                self._removeState(targetParent);

                var curIndex = self._keyCode(keyCode);
                if(curIndex > -1) {
                    // 除了列舉那些鍵碼不發請求
                    self._keyUpAndDown(targetVal,e,targetParent);
                }else {
                    // 渲染數據
                    self._renderHTML(targetVal,targetParent,elemHeight);

                    // 如果值為空的話 那么下拉列表隱藏掉
                    if(targetVal == '') {
                        self._hide(targetParent);
                        _cache.currentIndex = -1;
                        _cache.oldIndex = -1;
                    }else {
                        self._show(targetParent);
                    }
                }
            });
            
            var targetParent = $(item).closest(_config.parentCls);
            $(_config.selectCls,targetParent).unbind('click');
            $(_config.selectCls,targetParent).bind('click',function(){
                
                var targetVal = $.trim($(item,targetParent).val()),
                    elemHeight = $(item,targetParent).outerHeight();
                // 渲染數據
                self._renderHTML(targetVal,targetParent,elemHeight);
            });
        });

        /*
         * 點擊document 不包括input輸入框時候 隱藏下拉框
         */
        $(document).unbind('click');
        $(document).bind('click',function(e){
            e.stopPropagation();
            var target = e.target,
                targetParent = $(target).closest(_config.parentCls);
            var reg = _config.inputElemCls.replace(/^\./,''),
                selectCls = _config.selectCls.replace(/^\./,'');
            if($(target,targetParent).hasClass(reg) || $(target,targetParent).hasClass(selectCls)) {
                return;
            }else {
                self._hide(targetParent);
            }
            $(_config.inputElemCls).each(function(index,item){
                if(!$(item).hasClass('state')) {
                    $(item).val('');
                }
            });

        });
    },

 其中上面的 // 對input定義寬度 其父節點div也是根據input寬度定義的。 $(item).css({'width':_config.inputWidth}); var tagParent = $(item).closest(_config.parentCls); $(tagParent).css({'width':_config.inputWidth});

這幾句代碼的意思是:

   1 初始化時候 動態的設置input框的寬度 其中父元素的寬度也是根據input寬度來設置的,且下面的代碼 下拉框的寬度也是根據input寬度渲染的。

   2. 分別對input綁定keyup事件及下拉框小箭頭綁定點擊click事件做相應的操作。首先keyup操作時,調用這個方法 self._removeState(targetParent);刪除相應的class (state),因為下面有當我用鍵盤下拉移到某一項時或者鼠標點擊下拉框某一項時候 會增加class(state),這樣做的目的是當我點擊document時候會判斷input輸入框是否有這個class(state),如果沒有的話 清空input輸入框的值。否則的話,反之!接着判斷鍵碼 var curIndex = self._keyCode(keyCode); 這個方法.目的是為了當用上面那些鍵盤在輸入框操作時候 不發post請求(也就是說除了那些常見的鍵碼外發post請求)。如果鍵碼等於40的話 那么執行下移操作,如果等於38的話 那么是上移操作。否則的話 調用_renderHTML方法 渲染數據。(同樣當點擊下拉小箭頭時候也調用此方法渲染數據。),下面的代碼是點擊文檔document時候 首先判斷是否是輸入框或者是小箭頭的話,下拉框不做任何處理,否則的話 隱藏掉。點擊document時候 做了另外一件事,就是說 如果此input沒有state類名時候清空輸入框數據。

_renderHTML方法代碼如下:

_renderHTML: function(targetVal,targetParent,elemHeight) {
        var self = this,
            _config = self.config,
            _cache = self.cache;

            // 如果已經渲染了 先清空數據
            if($('ul',targetParent).length > 0) {
                self._show(targetParent);
                $('ul',targetParent).html('');
            }
            if(_cache.onlyCreate) {
                $(targetParent).append($('<ul></ul>'));
                _cache.onlyCreate = false;
            }
            var html = '';
            /*
             * 如果設置了靜態數據的話 那么直接使用靜態數據 否則的話 發post請求
             * 由於代碼沒有用 模板 所以直接for循環
             */ 
            if(_config.dataSource.length > 0) {
                

                for(var i = 0, ilen = _config.dataSource.length; i < ilen; i+=1) {
                    if(_config.dataSource[i].text.indexOf(targetVal) >= 0) {
                        html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+_config.dataSource[i].value+'" data-title="'+_config.dataSource[i].text+'">'+_config.dataSource[i].text+'</li>';
                    }else {
                        $('ul',targetParent).css({'border':'none'});
                    }
                }
                
                $('ul',targetParent).append(html);
            }else {
                // 發post請求
                /**$.ajax({
                    type: 'post'
                });**/

                // 假如返回的數據 如上所示的格式
                var result = [
                    {text: "列表項1", value: 1},
                    {text: "列表項2", value: 2},
                    {text: "列表項3", value: 3},
                    {text: "列表項4", value: 4},
                    {text: "列表項5", value: 5},
                    {text: "列表項6", value: 6},
                    {text: "列表項7", value: 7},
                    {text: "列表項8", value: 8},
                    {text: "列表項9", value: 9},
                    {text: "列表項10", value: 10},
                    {text: "列表項11", value: 11}
                ];
                for(var i = 0, ilen = result.length; i < ilen; i+=1) {
                    if(result[i].text.indexOf(targetVal) >=0) {
                        html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+result[i].value+'" data-title="'+result[i].text+'">'+result[i].text+'</li>';
                    }else {
                        $('ul',targetParent).css({'border':'none'});
                    }
                }
                $('ul',targetParent).append(html);
            }
            $('ul',targetParent).css({
                    "width":_config.inputWidth,
                    'overflow':'hidden','border':'1px solid #ccc','border-top':'none'});
            $('ul,li',targetParent).css({'cursor':'pointer'});
            
            var len = $('li',targetParent).length;
            if(len >= 10) {
                $('ul',targetParent).css({'height':'220px','overflow':'scroll'});
            }else {
                $('ul',targetParent).css({'height':'auto','overflow':'hidden'});
            }
        // hover事件
        self._hover(targetParent);        
        // 渲染后回調函數
        _config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback();

        // 點擊下來框某一項
        self._clickItem(targetParent);
    },

代碼做了如下事情:

  1. 如果ul已經創建了(只創建一次) 則顯示且清空之前的數據。

  2.如果設置了靜態數據的話(dataSource.length > 0) 那么直接使用靜態數據 否則的話 發post請求.

  3. 如果下拉框數據渲染時候 長度大於10的話 添加滾動條,否則的話 不添加。

接着就調用如下方法:

// hover事件
self._hover(targetParent); 

// 渲染后回調函數
_config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback();

// 點擊下來框某一項
self._clickItem(targetParent);

下面是所有的代碼如下:

HTML依賴的結構如下:

<div class="parentCls">
    <div class="drop-trigger"><i class="caret"></i></div>
    <input type="text" class="inputElem" autocomplete="off"/>
</div>

其中父級元素class默認為 parentCls,可以根據自己自定義 如有需要 可以根據具體的值進行傳,input的類名class 默認為inputElem 也可以自定義。

CSS代碼我就不貼了。可以根據自己的需要自己寫。如有需要或者可以看看JSfiddle源碼 看看css代碼。

下面是所有JS代碼如下:

/**
 * 一個解決大數據列表渲染效率的下拉菜單組件。
 * @author tugenhua
 * @time 2014-01-21
 */

 function DropList(options) {
    
    this.config = {
        parentCls        :  '.parentCls',       // 父元素class
        inputElemCls     :  '.inputElem',       // 當前input標簽input的class
        inputWidth       : 100,                 // 目標元素的寬度
        selectCls        :  '.caret',           // 下來小箭頭class
        hoverBg          : 'hoverBg',           // 鼠標移上去的背景
        isSelectHide     : true,                // 點擊下拉框 是否隱藏
        timeId           : 100,                 // 默認多少毫秒消失下拉框
        // 數據源返回的格式如下:靜態數據 否則的話(如果數組為空的話) 在內部發post請求
        dataSource: [
            {text: "列表項1", value: 1},
            {text: "列表項2", value: 2},
            {text: "列表項3", value: 3},
            {text: "列表項4", value: 4},
            {text: "列表項5", value: 5},
            {text: "列表項6", value: 6},
            {text: "列表項7", value: 7},
            {text: "列表項8", value: 8},
            {text: "列表項9", value: 9},
            {text: "列表項10", value: 10},
            {text: "列表項11", value: 11}
        ],
        renderHTMLCallback : null,                  // keyup時 渲染數據后的回調函數
        callback           : null                   // 點擊某一項 提供回調
    };

    this.cache = {
        onlyCreate          : true, // 只渲染一次代碼
        currentIndex        : -1,
        oldIndex            : -1,
        timeId              : null  // setTimeout定時器
    };
    this.init(options);
 }
 
 DropList.prototype = {
    
    constructor: DropList,
    
    init: function(options) {
        this.config = $.extend(this.config, options || {});
        var self = this,
            _config = self.config,
            _cache = self.cache;
        $('.drop-trigger').css({"left":_config.inputWidth - 20 + 'px'});
        /* 
         * 鼠標點擊輸入框時 渲染數據
         */
        $(_config.inputElemCls).each(function(index,item){
            
            // 對input定義寬度 其父節點div也是根據input寬度定義的。
            $(item).css({'width':_config.inputWidth});
            var tagParent = $(item).closest(_config.parentCls);
            $(tagParent).css({'width':_config.inputWidth});

            $(item).bind('keyup',function(e){
                e.preventDefault();
                var targetVal = $.trim($(this).val()),
                    keyCode = e.keyCode,
                    elemHeight = $(this).outerHeight();
                
                var targetParent = $(this).closest(_config.parentCls);
                $(targetParent).css({'position':'relative'});
                
                // 刪除標識
                self._removeState(targetParent);

                var curIndex = self._keyCode(keyCode);
                if(curIndex > -1) {
                    // 除了列舉那些鍵碼不發請求
                    self._keyUpAndDown(targetVal,e,targetParent);
                }else {
                    // 渲染數據
                    self._renderHTML(targetVal,targetParent,elemHeight);

                    // 如果值為空的話 那么下拉列表隱藏掉
                    if(targetVal == '') {
                        self._hide(targetParent);
                        _cache.currentIndex = -1;
                        _cache.oldIndex = -1;
                    }else {
                        self._show(targetParent);
                    }
                }
            });
            
            var targetParent = $(item).closest(_config.parentCls);
            $(_config.selectCls,targetParent).unbind('click');
            $(_config.selectCls,targetParent).bind('click',function(){
                
                var targetVal = $.trim($(item,targetParent).val()),
                    elemHeight = $(item,targetParent).outerHeight();
                // 渲染數據
                self._renderHTML(targetVal,targetParent,elemHeight);
            });
        });

        /*
         * 點擊document 不包括input輸入框時候 隱藏下拉框
         */
        $(document).unbind('click');
        $(document).bind('click',function(e){
            e.stopPropagation();
            var target = e.target,
                targetParent = $(target).closest(_config.parentCls);
            var reg = _config.inputElemCls.replace(/^\./,''),
                selectCls = _config.selectCls.replace(/^\./,'');
            if($(target,targetParent).hasClass(reg) || $(target,targetParent).hasClass(selectCls)) {
                return;
            }else {
                self._hide(targetParent);
            }
            $(_config.inputElemCls).each(function(index,item){
                if(!$(item).hasClass('state')) {
                    $(item).val('');
                }
            });

        });
    },
    // 鍵碼判斷
    _keyCode: function(code) {
        var arrs = ['17','18','38','40','37','39','33','34','35','46','36','13','45','44','145','19','20','9'];
        for(var i = 0, ilen = arrs.length; i < ilen; i++) {
            if(code == arrs[i]) {
                return i;
            }
        }
        return -1;
    },
    _renderHTML: function(targetVal,targetParent,elemHeight) {
        var self = this,
            _config = self.config,
            _cache = self.cache;

            // 如果已經渲染了 先清空數據
            if($('ul',targetParent).length > 0) {
                self._show(targetParent);
                $('ul',targetParent).html('');
            }
            if(_cache.onlyCreate) {
                $(targetParent).append($('<ul></ul>'));
                _cache.onlyCreate = false;
            }
            var html = '';
            /*
             * 如果設置了靜態數據的話 那么直接使用靜態數據 否則的話 發post請求
             * 由於代碼沒有用 模板 所以直接for循環
             */ 
            if(_config.dataSource.length > 0) {
                

                for(var i = 0, ilen = _config.dataSource.length; i < ilen; i+=1) {
                    if(_config.dataSource[i].text.indexOf(targetVal) >= 0) {
                        html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+_config.dataSource[i].value+'" data-title="'+_config.dataSource[i].text+'">'+_config.dataSource[i].text+'</li>';
                    }else {
                        $('ul',targetParent).css({'border':'none'});
                    }
                }
                
                $('ul',targetParent).append(html);
            }else {
                // 發post請求
                /**$.ajax({
                    type: 'post'
                });**/

                // 假如返回的數據 如上所示的格式
                var result = [
                    {text: "列表項1", value: 1},
                    {text: "列表項2", value: 2},
                    {text: "列表項3", value: 3},
                    {text: "列表項4", value: 4},
                    {text: "列表項5", value: 5},
                    {text: "列表項6", value: 6},
                    {text: "列表項7", value: 7},
                    {text: "列表項8", value: 8},
                    {text: "列表項9", value: 9},
                    {text: "列表項10", value: 10},
                    {text: "列表項11", value: 11}
                ];
                for(var i = 0, ilen = result.length; i < ilen; i+=1) {
                    if(result[i].text.indexOf(targetVal) >=0) {
                        html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+result[i].value+'" data-title="'+result[i].text+'">'+result[i].text+'</li>';
                    }else {
                        $('ul',targetParent).css({'border':'none'});
                    }
                }
                $('ul',targetParent).append(html);
            }
            $('ul',targetParent).css({
                    "width":_config.inputWidth,
                    'overflow':'hidden','border':'1px solid #ccc','border-top':'none'});
            $('ul,li',targetParent).css({'cursor':'pointer'});
            
            var len = $('li',targetParent).length;
            if(len >= 10) {
                $('ul',targetParent).css({'height':'220px','overflow':'scroll'});
            }else {
                $('ul',targetParent).css({'height':'auto','overflow':'hidden'});
            }
        // hover事件
        self._hover(targetParent);        
        // 渲染后回調函數
        _config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback();

        // 點擊下來框某一項
        self._clickItem(targetParent);
    },
    /*
     * 鍵盤上下移操作
     * @method _keyUpAndDown
     * @param  targetVal,e,targetParent
     */
    _keyUpAndDown: function(targetVal,e,targetParent){
        var self = this,
            _config = self.config,
            _cache = self.cache;

        // 如果請求成功后 返回了數據(根據元素的長度來判斷) 執行以下操作
        if($('li',targetParent) && $('li',targetParent).length > 0) {

            var plen = $('li',targetParent).length,
                keyCode = e.keyCode;
                _cache.oldIndex = _cache.currentIndex;
            // 上移操作
            if(keyCode == 38) {
                if(_cache.currentIndex == -1) {
                    _cache.currentIndex = plen - 1;
                }else {
                    _cache.currentIndex = _cache.currentIndex - 1;
                    if(_cache.currentIndex < 0) {
                        _cache.currentIndex = plen - 1;
                    }
                }
                if(_cache.currentIndex !== -1) {
    
                    !$($('li',targetParent)[_cache.currentIndex]).hasClass(_config.hoverBg) &&
                    $($('li',targetParent)[_cache.currentIndex]).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
                    var curAttr = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
                    $(_config.inputElemCls,targetParent).val(curAttr);

                    // 給當前的input元素增加一個標識
                    self._state(targetParent);
                    
                }

            }else if(keyCode == 40) { //下移操作
                if(_cache.currentIndex == plen - 1) {
                    _cache.currentIndex = 0;
                }else {
                    _cache.currentIndex++;
                    if(_cache.currentIndex > plen - 1) {
                        _cache.currentIndex = 0;
                    }
                }
                if(_cache.currentIndex !== -1) {
                    
                    !$($('li',targetParent)[_cache.currentIndex]).hasClass(_config.hoverBg) &&
                    $($('li',targetParent)[_cache.currentIndex]).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);

                    var curAttr = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
                    $(_config.inputElemCls,targetParent).val(curAttr);

                    // 給當前的input元素增加一個標識
                    self._state(targetParent);
                }
                
            }else if(keyCode == 13) { //回車操作
                var curVal = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
                $(_config.inputElemCls,targetParent).val(curVal);

                // 給當前的input元素增加一個標識
                self._state(targetParent);

                // 點擊下拉框某一項是否隱藏 下拉框 默認為true
                if(_config.isSelectHide) {
                    self._hide(targetParent);
                }
                _cache.currentIndex = -1;
                _cache.oldIndex = -1;
                
                // 點擊某一項后回調
                _config.callback && $.isFunction(_config.callback) && _config.callback();

                // 按enter鍵 阻止form表單默認提交
                return false;
                
            }
        }
    },
    // 給當前的input元素增加一個標識 目的是判斷輸入值是否合法
    _state: function(targetParent){
        var self = this,
            _config = self.config;
        !$(_config.inputElemCls,targetParent).hasClass('state') && 
         $(_config.inputElemCls,targetParent).addClass('state');
    },
    // 刪除input標識
    _removeState: function(targetParent) {
        var self = this,
            _config = self.config;
         $(_config.inputElemCls,targetParent).hasClass('state') && 
         $(_config.inputElemCls,targetParent).removeClass('state');
    },
    /*
     * hover 下拉框
     */
    _hover: function(targetParent){
        var self = this,
            _config = self.config;
        
        $('.dropmenu-item',targetParent).each(function(index,item){
            $(item).hover(function(){
                !$(item).hasClass(_config.hoverBg) && $(item).addClass(_config.hoverBg);
            },function(){
                $(item).hasClass(_config.hoverBg) && $(item).removeClass(_config.hoverBg);
            });
        })
    },
    /*
     * 點擊下拉框某一項
     * @method _clickItem
     */
    _clickItem: function(targetParent) {
        var self = this,
            _config = self.config;
        $('.dropmenu-item',targetParent).each(function(index,item){
            
            $(item).unbind('click');
            $(item).bind('click',function(e){
                var target = e.target,
                    title = $(target).attr('data-title');
                $(_config.inputElemCls,targetParent).val(title);

                // 給當前的input元素增加一個標識 目的是判斷輸入值是否合法
                !$(_config.inputElemCls,targetParent).hasClass('state') && 
                 $(_config.inputElemCls,targetParent).addClass('state');

                // 點擊某一項后回調
                _config.callback && $.isFunction(_config.callback) && _config.callback();

                // 點擊下拉框某一項是否隱藏 下拉框 默認為true
                if(_config.isSelectHide) {
                    self._hide(targetParent);
                }
            });
        });
    },
    /*
     * 顯示方法
     * @mrthod _show {private}
     */
    _show: function(targetParent) {
        var self = this,
            _config = self.config,
            _cache = self.cache;
        _cache.timeId && clearTimeout(_cache.timeId);
        if($('ul',targetParent).hasClass('hidden')) {
            $('ul',targetParent).removeClass('hidden');
        }
    },
    /*
     * 隱藏方法
     * @method _hide {private}
     */
    _hide: function(targetParent) {
        var self = this,
            _config = self.config,
            _cache = self.cache;
        _cache.timeId = setTimeout(function(){
            if($(targetParent).length > 0) {
                !$('ul',targetParent).hasClass('hidden') && $('ul',targetParent).addClass('hidden');
            }else {
                !$('ul').hasClass('hidden') && $('ul').addClass('hidden');
            }
        },_config.timeId);
    },
    /*
     * 給輸入框設置默認值
     * @param {Object}
     * @method setValue {public}
     */
    setValue: function(obj){
        /** 對象格式如下
        // 設置初始化選擇項。
        selectedItem: {
            value: "4",
            text: "列表項4"
        }**/
        var self = this,
            _config = self.config;
        $(_config.inputElemCls).val(obj.text);
    },
    /*
     * 獲取輸入框的值
     * @return value
     */
    getValue: function() {
        var self = this,
            _config = self.config;
        return $(_config.inputElemCls).val();
    }
 };
 // 初始化
 $(function(){
    var a = new DropList({
        dataSource: []
    });
    var selectedItem = {
        value: "4",
        text: "列表項4"
    };
    a.setValue(selectedItem);
 });
View Code

插件不足之處:

 1. 在火狐或者google下 當下拉框下拉時候 按上移鍵 光標會先跳到最前面然后移到最后面,也就是說光標會移動,用戶體驗稍微有點不好,一般情況下,用戶也不會用上下移鍵,一般用鼠標操作,但是這也是一個小bug,目前沒有找到具體的原因。我想可以用HTML5中的Range對象和 selection對象應該有辦法解決!后續有時間的話 稍微解決這么一個bug。

 2. 第二個不足之處,就是當數據量大的時候(比如數據下拉框有2000條數據甚至更多時候),前端性能肯定會有影響。淘寶kissy他是用的是對返回的數組分批渲染,但是還是有影響的,目前沒有發現有什么的更好的方法來解決這么一個大數據的情況。

針對下拉框大數據的時候的個人想法:

   首先我們明白 在窗口中頁面上假如有10000張圖片,我們根據 圖片離瀏覽器頂部的距離是否小於或者等於 可視區離瀏覽器頂部的距離 進行延遲加載渲染圖片,可以有效的提高性能,只加載第一屏幕的數據。那么這個下拉框我們是否也可以根據這個原理也對它做這樣的處理:比如頁面一開始渲染的時候 我只加載10條數據且有滾動條,那么當我下拉滾動條時候再進行分批渲染相應的數據,不管后台返回我的是10000條數據也好或者更多,我們只關注且頁面一開始只渲染前面10條數據,后面的數據根據用戶操作下拉滾動條時候進行分別渲染出來,雖然目前我們前端是沒有辦法監聽這個事件的。目前也沒有辦法做到的,但是我今天站在用戶角度來考慮這么一個問題的。或許隨着時間越長,未來的技術可以解決這么一個問題的。期待中.......

總結:

   2014年春節前,這篇博客有可能是最后一篇了,如有不足之處,請大家多多指教!已經買了28號凌晨2點的火車回家,嘿嘿!明年繼續研究代碼,研究前端技術,分享HTML5+CSS3的一些東西出來,及正要學習 數據結構與算法。2013年9月份左右在博客園有了自己的博客,時間匆匆而過,在博客園快有半年了!嗨!最后也祝福大家早點回家過年!路上一路順風!時間也不早了,我也要休息!明天還要上班,感覺最后一個星期時間過得很慢很慢!嗨!

DEMO下載:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM