javascript代码实例教程-JS列表的下拉菜单组件(仿美化控件select)

发布时间:2019-02-09 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-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定义宽度 其父节点p也是根据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定义宽度 其父节点p也是根据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) &amp;& _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依赖的结构如下:

 

<p class="parentCls">

    <p class="drop-trigger"><i class="caret"></i></p>

    <input type="text" class="inputElem" autocomplete="off"/>

</p>

其中父级元素class默认为 parentCls,可以根据自己自定义 如有需要 可以根据具体的值进行传,input的类名class 默认为inputElem 也可以自定义。

 

CSS代码我就不贴了。可以根据自己的需要自己写。如有需要或者可以看看JSfiddle源码 看看css代码。

 

下面是所有JS代码如下:

 

 View Code

插件不足之处:

 1. 在火狐或者GOOGLE下 当下拉框下拉时候 按上移键 光标会先跳到最前面然后移到最后面,也就是说光标会移动,用户体验稍微有点不好,一般情况下,用户也不会用上下移键,一般用鼠标操作,但是这也是一个小bug,目前没有找到具体的原因。我想可以用HTML5中的Range对象和 selection对象应该有办法解决!后续有时间的话 稍微解决这么一个bug。

 

 2. 第二个不足之处,就是当数据量大的时候(比如数据下拉框有2000条数据甚至更多时候),前端性能肯定会有影响。淘宝kissy他是用的是对返回的数组分批渲染,但是还是有影响的,目前没有发现有什么的更好的方法来解决这么一个大数据的情况。

 

针对下拉框大数据的时候的个人想法:

   首先我们明白 在窗口中页面上假如有10000张图片,我们根据 图片离浏览器顶部的距离是否小于或者等于 可视区离浏览器顶部的距离 进行延迟加载渲染图片,可以有效的提高性能,只加载第一屏幕的数据。那么这个下拉框我们是否也可以根据这个原理也对它做这样的处理:比如页面一开始渲染的时候 我只加载10条数据且有滚动条,那么当我下拉滚动条时候再进行分批渲染相应的数据,不管后台返回我的是10000条数据也好或者更多,我们只关注且页面一开始只渲染前面10条数据,后面的数据根据用户操作下拉滚动条时候进行分别渲染出来,虽然目前我们前端是没有办法监听这个事件的。目前也没有办法做到的,但是我今天站在用户角度来考虑这么一个问题的。或许随着时间越长,未来的技可以解决这么一个问题的。期待中.......

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-JS列表的下拉菜单组件(仿美化控件select)全部内容,希望文章能够帮你解决javascript代码实例教程-JS列表的下拉菜单组件(仿美化控件select)所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。