自定义可输入的下拉列表

简单易用,绑定一个div就能生成下拉列表
new Selector()的参数1:HTMLDivElement或div元素的id:,参数2(可选):选项数据的数组,参数3(可选):文本框值或选项改变时的回调函数(value, index, selector),下面有例子

方法介绍,除getValue()方法外的其他方法都支持链式调用Selector的自定义方法

方法 方法作用 其它说明
setBoxCss(json) 修改文本框样式 可传入任意div支持的样式
setPanelCss(json) 修改下拉列表面板样式 可传入任意div支持的样式
setItemCss(json) 修改下拉列表选项正常样式 可传入任意div支持的样式
setItemHoverCss(json) 修改下拉列表选项正hover样式 可传入任意div支持的样式
setOptions(array,bool) 设置选项 参数2为true代表临时设置,主要是过滤器用的
setCallback(function) 设置文本框值改变或选项改变时的回调方法 回调有三个参数,对应值和索引和Selector本身引用,可在此调用它的方法
setFilter(function, bool) 设置选项过滤器 回调返回选项值,返回false移除该选项,第一个参数传null不会修改过滤器,第二个参数可为true关闭过滤器
getOptsFromServer(json, function) 通过url加载选项 json是请求选项{url,method(可选),参数(可选)}回调作为数据适配器返回url请求响应的数据,默认适配器把data作为选项数据,可以在此对数据进行处理确保返回一个数组作为选项数据
updatePostParams(json) 更新搜素参数,根据关键字重新索索
doFilter(string) 主动过滤选项 string是过滤关键字,在过滤器关闭时无效
showPanel() 主动显示下拉面板
hidePanel() 主动隐藏下拉面板
getValue() 获取文本框的值 返回string不可以在其后链式调Selector其它自定义方法
setValue(string) 设置文本框的值  

效果图:


注:需依赖jquery,我用的是jquery1.11.3.min.js

Selectord代码
function Selector(id, options, callback) {
        this.options = options || []; // 选项数据数
        this.tempOptions = [];
        this.callback = callback || function () {}; // 选项改变或文本框内容改变时的回调处理函数
        this.urlOp = {};    // 请求,包含地址:url,请求方式:method,参数:data
        this.dataAdapter = function () {}; // 数据适配器,如果返回数据不是数组需用此方法转化为数组做为选项数据
        this.runFilter = false; // 文本输入时是否对选项进行过滤
        this.filter = function (value, key) {
            value = value || '';
            key = key || '';
            return value.indexOf(key) >= 0 || key.indexOf(value) >= 0;
        }; // 选项过滤器,默认关闭

        if(id && id.constructor == HTMLDivElement) {
            this.ele = id;
        } else {
            this.ele = document.getElementById(id);
        }
        if(!this.ele || this.ele.constructor != HTMLDivElement) {
            console.error('error id of div element bing on selector');
            return {};
        }
        if(this.ele.tagName != 'DIV') {
            console.error('please bind on div element');
            return {};
        }

        this.defBoxCss = {
            'padding-right':'20px',
            'background':'url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiA8Zz4KICA8cmVjdCB4PSItMSIgeT0iLTEiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyMiIgaWQ9ImNhbnZhc19iYWNrZ3JvdW5kIiBmaWxsPSJub25lIi8+CiA8L2c+CiA8Zz4KICA8cG9seWdvbiBwb2ludHM9IjEyLjcxNDYwNzY4NTgwNDM2Nyw3LjYyOTAyMjU5ODI2NjYwMiA4LjI4Mzk2NjUxMTQ4Nzk2LDEzLjA2OTEwMzI0MDk2Njc5NyAzLjg1MzMyNzcyMTM1NzM0NTYsNy42MjkwMjI1OTgyNjY2MDIgIiBpZD0ic3ZnXzEiIHN0cm9rZT0ibnVsbCIvPgogPC9nPgo8L3N2Zz4=) no-repeat 100% center'
        };
        this.defPanelCss = {
            'position': 'absolute',
            'background-color': '#fff',
            'z-index': '999999999',
            'padding': '1px',
            'transition': 'width 0.5s',
            'overflow': 'auto'
        };

        this.defListItemCss = {
            'background-color': '#fff',
            'height': '30px',
            'veritical-align': 'middle',
            'padding' : '3px',
            'margin-top': '1px',
            'cursor': 'pointer'
        };

        this.defListItemHoverCss = {
            'background-color': '#0ebebe'
        };

        var w = $(this.ele).innerWidth();
        var h = $(this.ele).innerHeight();

        this.input = document.createElement('input');
        $(this.selectorListPanel).css(this.defPanelCss);
        this.input.style.width = w+'px';
        this.input.style.height = h+'px';
        this.input.style.padding = '3px';
        $(this.input).css(this.defBoxCss);
        this.ele.appendChild(this.input);

        this.selectorListPanel = document.createElement('div');
        $(this.selectorListPanel).css(this.defPanelCss);

        this.selectorListPanel.style.position = 'fixed';
        this.selectorListPanel.style.display = 'none';
        this.selectorListPanel.tabIndex = '0';
        this.ele.appendChild(this.selectorListPanel);

        this.listItems = [];
        this.index = 0;

        var value = this.input.value || '';
        var obj = this;
        var hoverIndex = 0;

        this.input.addEventListener('blur', function () {
            if(value || obj.options[hoverIndex] == value || obj.tempOptions[hoverIndex] == value) {
                obj.selected(hoverIndex);
                if(obj.callback && obj.callback.constructor == Function) {
                    obj.callback(value, obj.index, obj);
                    obj.doFilter(value);
                }
            }
            obj.selectorListPanel.style.display = 'none';
        });

        this.input.addEventListener('focus', function (e) {
            obj.showPanel();
        });

        this.input.addEventListener('input', function () {
            value = obj.input.value;
            if(obj.callback && obj.callback.constructor == Function) {
                obj.callback(value, -1, obj);
                obj.doFilter(value);
            }
        });


        this.setBoxCss = function (css) {
            for (var p in css) {
                obj.defBoxCss[p] = css[p];
            }
            $(this.input).css(obj.defBoxCss);
            return obj;
        };

        this.setPanelCss = function (css) {
            for (var p in css) {
                obj.defPanelCss[p] = css[p];
            }
            $(obj.selectorListPanel).css(obj.defPanelCss);
            return obj;
        };

        this.setItemCss = function(css) {
            for (var p in css) {
                obj.defListItemCss[p] = css[p];
            }
            obj.setOptions(obj.options);
            return obj;
        }

        this.setItemHoverCss = function(hoverCss) {
            for (var p in hoverCss) {
                obj.defListItemHoverCss[p] = hoverCss[p];
            }
            return obj;
        };

        this.setOptions = function (opts, isTemp) {
            if(!opts || opts.constructor != Array) {
                return obj;
            }
            if(!isTemp) {
                obj.options = opts.slice(0);
            } else {
                obj.tempOptions = opts.slice(0);
            }
            obj.selectorListPanel.innerHTML = '';
            obj.listItems = [];
            for(var i in opts) {
                var listItem = document.createElement('div');
                $(listItem).css(obj.defListItemCss);
                listItem.textContent = opts[i];

                listItem.addEventListener('click', function (e) {
                    obj.selected(hoverIndex);
                    obj.selectorListPanel.style.display = 'none';
                });

                listItem.addEventListener('mouseover', function (e) {
                    $(this).css(obj.defListItemHoverCss);
                    if(!obj.defListItemHoverCss['line-height']) {
                        this.style.lineHeight = listItem.clientHeight + 'px';
                    }
                    value  = this.textContent;
                    hoverIndex = this.getAttribute('index');
                });

                listItem.addEventListener('mouseout', function (e) {
                    if(obj.index == this.getAttribute('index')) {
                        return;
                    }
                    $(this).css(obj.defListItemCss);
                    value = obj.input.value;
                });
                listItem.setAttribute('index', i);
                obj.selectorListPanel.appendChild(listItem);
                obj.listItems.push(listItem);
            }
            if(!isTemp && !obj.input.value && opts.length > 0) {
                obj.selected(0);
            }
            return obj;
        };

        this.setCallback = function(calllback){
            if(calllback && calllback.constructor == Function) {
                obj.callback = calllback;
            } else {
                console.error('Selector ERR: callback not is Function');
            }
            return obj;
        };

        this.setFilter = function(filter, isOff) {
            obj.runFilter = !isOff;
            if(filter && filter) {
                obj.filter = filter;
            }
            return obj;
        }

        this.getOptsFromServer = function (op, dataAdapter) {
            if(!op) {
                console.error('Selector ERR: invalid parameter');
                return obj;
            }

            obj.urlOp = op;
            $.ajax({
                url: op.url,
                type: op.method || 'GET',
                dataType: 'json',
                data: op.data || {},
                async: false,
                success: function (data) {
                    var arr = null;
                    if(dataAdapter && dataAdapter.constructor == Function) {
                        obj.dataAdapter = dataAdapter;
                        arr = obj.dataAdapter(data);
                    } else {
                        arr = data;
                    }
                    if(arr && arr.dataAdapter.constructor == Array)
                    {
                        obj.setOptions(arr);
                    } else {
                        console.error('Selector ERR: invalid data');
                    }
                },
                error: function (err) {
                    console.error('Selector ERR:');
                    console.error(err);
                }
            });
            return obj;
        };

        //用以搜索
        this.updatePostParams = function(data) {
            obj.urlOp.data = data;
            obj.getOptsFromServer(obj.urlOp, obj.dataAdapter);
        }

        this.selected = function(idx) {
            if(idx >= 0 && idx < obj.options.length) {
                $(obj.listItems[obj.index]).css(obj.defListItemCss);
                $(obj.listItems[idx]).css(obj.defListItemHoverCss);
                obj.input.value = value = this.options[idx];
                obj.input.value = obj.listItems[idx].textContent;
                obj.index = idx;
            }
            return obj;
        };

        this.getValue = function () {
            return obj.input.value;
        };

        this.setValue = function (text) {
            obj.input.value = text;
        };

        this.showPanel= function() {
            if(obj.options.length == 0) {
                return obj;
            }
            var w = $(obj.input).innerWidth();
            var h = $(obj.input).innerHeight();
            var ch = this.ele.clientHeight;
            var left = $(obj.input).offset().left - document.documentElement.scrollLeft;
            var top = $(obj.input).offset().top - document.documentElement.scrollTop;
            var panelHeight = $(this.selectorListPanel).height();

            obj.selectorListPanel.style.width = w+'px';
            obj.selectorListPanel.style.maxHeight =  $(window).height()/2+'px';

            var panelTop = top+5+h;
            obj.selectorListPanel.style.top = panelTop+'px';
            obj.selectorListPanel.style.boxShadow= '1px 1px 3px rgba(1, 1, 1, 0.77)';

            if(panelTop+panelHeight > $(window).height()) {
                var panelTop = top-5-$(obj.selectorListPanel).height();
                obj.selectorListPanel.style.top = panelTop+'px';
                obj.selectorListPanel.style.boxShadow= '1px -1px 3px rgba(1, 1, 1, 0.77)';
            }
            obj.selectorListPanel.style.display = 'block';
            return obj;
        };

        this.hidePanel = function() {
            obj.selectorListPanel.style.display = 'none';
        }

        this.doFilter = function (key) {
            if(obj.runFilter && obj.filter && obj.filter.constructor == Function) {
                obj.setOptions(obj.options.filter(function (item) {
                    return obj.filter(item, key);
                }), true);
                obj.index = hoverIndex = 0;
                obj.showPanel();
            }
            return obj;
        }

        window.addEventListener('resize', function (ev) {
            if(obj.selectorListPanel.style.display == 'block') {
                obj.showPanel();
            }
        });

        window.addEventListener('scroll', function (ev) {
            if(obj.selectorListPanel.style.display == 'block') {
                obj.showPanel();
            }
        });

        this.setOptions(obj.options);
    }

下面是包含示例代码和说明的网页源码

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <style type="text/css">
        .sele {
            margin-left: 400px;
            width: 200px;
            height: 30px;
            margin-top: 100px;
        }

    </style>
</head>

<body>
<div style="height: 600px;background-color: #efefef; overflow: scroll;">
    <div>简单易用,绑定一个div就能生成下拉列表</div>
    <div>new Selector()的参数1:HTMLDivElement或div元素的id:,参数2:选项数据的数组,参数3:文本框值或选项改变时的回调函数(value, index),下面有例子</div>
    <table border="1" cellpadding="0">
        <title>Selector的方法介绍,除getValue()方法外的其他方法都支持链式调用Selector的自定义方法</title>
        <thead>
            <th>方法</th>
            <th>方法作用</th>
            <th>其它说明</th>
        </thead>
        <tbody>
            <tr>
                <td>setBoxCss(json)</td>
                <td>修改文本框样式</td>
                <td>可传入任意div支持的对象</td>
            </tr>
            <tr>
                <td>setPanelCss(json)</td>
                <td>修改下拉列表面板样式</td>
                <td>可传入任意div支持的对象</td>
            </tr>
            <tr>
                <td>setItemCss(json)</td>
                <td>修改下拉列表选项正常样式</td>
                <td>可传入任意div支持的对象</td>
            </tr>
            <tr>
                <td>setItemHoverCss(json)</td>
                <td>修改下拉列表选项正hover样式</td>
                <td>可传入任意div支持的对象</td>
            </tr>
            <tr>
                <td>setOptions(array,bool)</td>
                <td>设置选项</td>
                <td>参数2为true代表临时设置,主要是过滤器用的</td>
            </tr>
            <tr>
                <td>setCallback(function)</td>
                <td>设置文本框值改变或选项改变时的回调方法</td>
                <td>回调有三个参数,对应值和索引和Selector本身引用,可在此调用它的方法</td>
            </tr>
            <tr>
                <td>setFilter(function, bool)</td>
                <td>设置选项过滤器</td>
                <td>回调返回选项值,返回false移除该选项,第一个参数传null不会修改过滤器,第二个参数可为true关闭过滤器</td>
            </tr>
            <tr>
                <td>getOptsFromServer(json, function)</td>
                <td>通过url加载选项</td>
                <td>json是请求选项{url,method(可选),参数(可选)}回调作为数据适配器返回url请求响应的数据,默认适配器把data作为选项数据,可以在此对数据进行处理确保返回一个数组作为选项数据</td>
            </tr>
            <tr>
                <td>updatePostParams(json)</td>
                <td>更新搜素参数,根据关键字重新索索</td>
            </tr>
            <tr>
                <td>doFilter(string)</td>
                <td>主动过滤选项</td>
                <td>string是过滤关键字,在过滤器关闭时无效</td>
            </tr>
            <tr>
                <td>showPanel()</td>
                <td>主动显示下拉面板</td>
            </tr>
            <tr>
                <td>hidePanel()</td>
                <td>主动隐藏下拉面板</td>
            </tr>
            <tr>
                <td>getValue()</td>
                <td>获取文本框的值</td>
                <td>返回string不可以在其后链式调Selector其它自定义方法</td>
            </tr>
            <tr>
                <td>setValue(string)</td>
                <td>设置文本框的值</td>
                <td></td>
            </tr>
        </tbody>
    </table>
    <h3>注:需依赖jquary</h3>
    <h5>Selector使用例子1</h5>
    <pre>
        //Selector的参数1:HTMLDivElement或div元素的id:,参数2:选项数据的数组,参数3:文本框值或选项改变时的回调函数(value, index)

        var st1 = new Selector(s1, ['a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], function (value, index, selector) {
        console.log(value, index);
        }).selected(3);
        //重置opations
        //st1.setOptions(['a','v','c']);
    </pre>
    <h5>Selector使用例子2</h5>
    <pre>
        new Selector('s2').setBoxCss({'width':'300px', 'height':'50px'}).setOptions(['1','2','3','4'])
        .setItemCss({'height':'60px'}).setItemHoverCss({'background':'#0d71bb'})
        .setCallback(function (value, index) {
            console.log(value, index);
        });
    </pre>
    <h5>Selector使用例子3</h5>
    <pre>
        new Selector('s3').getOptsFromServer({'url':'https:xxxx'}).setCallback(function (value, index) {
            console.log(value, index);
        });
    </pre>
    <h5>Selector使用例子4(搜索)</h5>
    <pre>
        //搜索例子
        new Selector('s4').getOptsFromServer({'url':'https:xxxx'}, function (data) {
            return data.list; //数据适配器对data进行处理,返回数组做为选项
        }).setCallback(function (value, index, selector) { //选项发送变化
            selector.updatePostParams({key:value}); //更新参数重新请求
            console.log(value, index);
        });
    </pre>
    <h5>Selector使用例子5(使用默认过滤器和自定义选项过滤器)</h5>
    <pre>
        new Selector('s5', ['a1', 'a2', 'a3', 'a4']).setCallback(function (v,i) {
            console.log(v+','+i);
         }).selected(1).setFilter(null); //打开默认选项过滤器

        new Selector(s6, ['','a1', 'a2', 'a3', 'a4']).setCallback(function (v,i) {
            console.log(v+','+i);
        }).setFilter(function (item, key) { //选项过滤器
            return (item || '').indexOf(key) >= 0;
        });
    </pre>
</div>
<div id='s1' class="sele"></div>
<div id='s2' class="sele"></div>
<div id='s3' class="sele"></div>
<div id='s4' class="sele"></div>
<div id='s5' class="sele"></div>
<div id='s6' class="sele"></div>
<div style="height: 1000px; width: 20px;background-color: #0d71bb"></div>
<script type="text/javascript" src="jquery1.11.3.min.js"></script>
<script type="text/javascript">

    
    new Selector(s1, ['a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7']).setCallback(function (v,i) {
        console.log(v+','+i);
    }).selected(2);

    new Selector('s2').setOptions(['1','2','3','4']).setCallback(function (value, index) {
            console.log(value, index);
    }).setBoxCss({'width':'300px', 'height':'50px', 'border-radius':'5px'}).setItemCss({'height':'60px'}).setItemHoverCss({'background':'#75b4bb'});

    new Selector('s3').getOptsFromServer({url:'https:xxxx', method:'post', data:{key:''}}).setCallback(function (value, index) {
        console.log(value, index);
    });

    //搜索例子
    new Selector('s4').getOptsFromServer({'url':'https:xxxx'}, function (data) {
        return data.list; //数据适配器对data进行处理,返回数组做为选项
    }).setCallback(function (value, index, selector) { //选项发送变化
        selector.updatePostParams({key:value}); //更新参数重新请求
        console.log(value, index);
    });

    new Selector('s5', ['a1', 'a2', 'a3', 'a4']).setCallback(function (v,i) {
        console.log(v+','+i);
    }).selected(2).setFilter(null); //打开默认选项过滤器

    new Selector(s6, ['a1', 'a2', 'a3', 'a4']).setCallback(function (v,i) {
        console.log(v+','+i);
    }).setFilter(function (item, key) { //自定义选项过滤器
        return (item || '').indexOf(key) >= 0;
    });

    function Selector(id, options, callback) {
        this.options = options || []; // 选项数据数
        this.tempOptions = [];
        this.callback = callback || function () {}; // 选项改变或文本框内容改变时的回调处理函数
        this.urlOp = {};    // 请求,包含地址:url,请求方式:method,参数:data
        this.dataAdapter = function () {}; // 数据适配器,如果返回数据不是数组需用此方法转化为数组做为选项数据
        this.runFilter = false; // 文本输入时是否对选项进行过滤
        this.filter = function (value, key) {
            value = value || '';
            key = key || '';
            return value.indexOf(key) >= 0 || key.indexOf(value) >= 0;
        }; // 选项过滤器,默认关闭

        if(id && id.constructor == HTMLDivElement) {
            this.ele = id;
        } else {
            this.ele = document.getElementById(id);
        }
        if(!this.ele || this.ele.constructor != HTMLDivElement) {
            console.error('error id of div element bing on selector');
            return {};
        }
        if(this.ele.tagName != 'DIV') {
            console.error('please bind on div element');
            return {};
        }

        this.defBoxCss = {
            'padding-right':'20px',
            'background':'url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiA8Zz4KICA8cmVjdCB4PSItMSIgeT0iLTEiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyMiIgaWQ9ImNhbnZhc19iYWNrZ3JvdW5kIiBmaWxsPSJub25lIi8+CiA8L2c+CiA8Zz4KICA8cG9seWdvbiBwb2ludHM9IjEyLjcxNDYwNzY4NTgwNDM2Nyw3LjYyOTAyMjU5ODI2NjYwMiA4LjI4Mzk2NjUxMTQ4Nzk2LDEzLjA2OTEwMzI0MDk2Njc5NyAzLjg1MzMyNzcyMTM1NzM0NTYsNy42MjkwMjI1OTgyNjY2MDIgIiBpZD0ic3ZnXzEiIHN0cm9rZT0ibnVsbCIvPgogPC9nPgo8L3N2Zz4=) no-repeat 100% center'
        };
        this.defPanelCss = {
            'position': 'absolute',
            'background-color': '#fff',
            'z-index': '999999999',
            'padding': '1px',
            'transition': 'width 0.5s',
            'overflow': 'auto'
        };

        this.defListItemCss = {
            'background-color': '#fff',
            'height': '30px',
            'veritical-align': 'middle',
            'padding' : '3px',
            'margin-top': '1px',
            'cursor': 'pointer'
        };

        this.defListItemHoverCss = {
            'background-color': '#0ebebe'
        };

        var w = $(this.ele).innerWidth();
        var h = $(this.ele).innerHeight();

        this.input = document.createElement('input');
        $(this.selectorListPanel).css(this.defPanelCss);
        this.input.style.width = w+'px';
        this.input.style.height = h+'px';
        this.input.style.padding = '3px';
        $(this.input).css(this.defBoxCss);
        this.ele.appendChild(this.input);

        this.selectorListPanel = document.createElement('div');
        $(this.selectorListPanel).css(this.defPanelCss);

        this.selectorListPanel.style.position = 'fixed';
        this.selectorListPanel.style.display = 'none';
        this.selectorListPanel.tabIndex = '0';
        this.ele.appendChild(this.selectorListPanel);

        this.listItems = [];
        this.index = 0;

        var value = this.input.value || '';
        var obj = this;
        var hoverIndex = 0;

        this.input.addEventListener('blur', function () {
            if(value || obj.options[hoverIndex] == value || obj.tempOptions[hoverIndex] == value) {
                obj.selected(hoverIndex);
                if(obj.callback && obj.callback.constructor == Function) {
                    obj.callback(value, obj.index, obj);
                    obj.doFilter(value);
                }
            }
            obj.selectorListPanel.style.display = 'none';
        });

        this.input.addEventListener('focus', function (e) {
            obj.showPanel();
        });

        this.input.addEventListener('input', function () {
            value = obj.input.value;
            if(obj.callback && obj.callback.constructor == Function) {
                obj.callback(value, -1, obj);
                obj.doFilter(value);
            }
        });


        this.setBoxCss = function (css) {
            for (var p in css) {
                obj.defBoxCss[p] = css[p];
            }
            $(this.input).css(obj.defBoxCss);
            return obj;
        };

        this.setPanelCss = function (css) {
            for (var p in css) {
                obj.defPanelCss[p] = css[p];
            }
            $(obj.selectorListPanel).css(obj.defPanelCss);
            return obj;
        };

        this.setItemCss = function(css) {
            for (var p in css) {
                obj.defListItemCss[p] = css[p];
            }
            obj.setOptions(obj.options);
            return obj;
        }

        this.setItemHoverCss = function(hoverCss) {
            for (var p in hoverCss) {
                obj.defListItemHoverCss[p] = hoverCss[p];
            }
            return obj;
        };

        this.setOptions = function (opts, isTemp) {
            if(!opts || opts.constructor != Array) {
                return obj;
            }
            if(!isTemp) {
                obj.options = opts.slice(0);
            } else {
                obj.tempOptions = opts.slice(0);
            }
            obj.selectorListPanel.innerHTML = '';
            obj.listItems = [];
            for(var i in opts) {
                var listItem = document.createElement('div');
                $(listItem).css(obj.defListItemCss);
                listItem.textContent = opts[i];

                listItem.addEventListener('click', function (e) {
                    obj.selected(hoverIndex);
                    obj.selectorListPanel.style.display = 'none';
                });

                listItem.addEventListener('mouseover', function (e) {
                    $(this).css(obj.defListItemHoverCss);
                    if(!obj.defListItemHoverCss['line-height']) {
                        this.style.lineHeight = listItem.clientHeight + 'px';
                    }
                    value  = this.textContent;
                    hoverIndex = this.getAttribute('index');
                });

                listItem.addEventListener('mouseout', function (e) {
                    if(obj.index == this.getAttribute('index')) {
                        return;
                    }
                    $(this).css(obj.defListItemCss);
                    value = obj.input.value;
                });
                listItem.setAttribute('index', i);
                obj.selectorListPanel.appendChild(listItem);
                obj.listItems.push(listItem);
            }
            if(!isTemp && !obj.input.value && opts.length > 0) {
                obj.selected(0);
            }
            return obj;
        };

        this.setCallback = function(calllback){
            if(calllback && calllback.constructor == Function) {
                obj.callback = calllback;
            } else {
                console.error('Selector ERR: callback not is Function');
            }
            return obj;
        };

        this.setFilter = function(filter, isOff) {
            obj.runFilter = !isOff;
            if(filter && filter) {
                obj.filter = filter;
            }
            return obj;
        }

        this.getOptsFromServer = function (op, dataAdapter) {
            if(!op) {
                console.error('Selector ERR: invalid parameter');
                return obj;
            }

            obj.urlOp = op;
            $.ajax({
                url: op.url,
                type: op.method || 'GET',
                dataType: 'json',
                data: op.data || {},
                async: false,
                success: function (data) {
                    var arr = null;
                    if(dataAdapter && dataAdapter.constructor == Function) {
                        obj.dataAdapter = dataAdapter;
                        arr = obj.dataAdapter(data);
                    } else {
                        arr = data;
                    }
                    if(arr && arr.dataAdapter.constructor == Array)
                    {
                        obj.setOptions(arr);
                    } else {
                        console.error('Selector ERR: invalid data');
                    }
                },
                error: function (err) {
                    console.error('Selector ERR:');
                    console.error(err);
                }
            });
            return obj;
        };

        //用以搜索
        this.updatePostParams = function(data) {
            obj.urlOp.data = data;
            obj.getOptsFromServer(obj.urlOp, obj.dataAdapter);
        }

        this.selected = function(idx) {
            if(idx >= 0 && idx < obj.options.length) {
                $(obj.listItems[obj.index]).css(obj.defListItemCss);
                $(obj.listItems[idx]).css(obj.defListItemHoverCss);
                obj.input.value = value = this.options[idx];
                obj.input.value = obj.listItems[idx].textContent;
                obj.index = idx;
            }
            return obj;
        };

        this.getValue = function () {
            return obj.input.value;
        };

        this.setValue = function (text) {
            obj.input.value = text;
        };

        this.showPanel= function() {
            if(obj.options.length == 0) {
                return obj;
            }
            var w = $(obj.input).innerWidth();
            var h = $(obj.input).innerHeight();
            var ch = this.ele.clientHeight;
            var left = $(obj.input).offset().left - document.documentElement.scrollLeft;
            var top = $(obj.input).offset().top - document.documentElement.scrollTop;
            var panelHeight = $(this.selectorListPanel).height();

            obj.selectorListPanel.style.width = w+'px';
            obj.selectorListPanel.style.maxHeight =  $(window).height()/2+'px';

            var panelTop = top+5+h;
            obj.selectorListPanel.style.top = panelTop+'px';
            obj.selectorListPanel.style.boxShadow= '1px 1px 3px rgba(1, 1, 1, 0.77)';

            if(panelTop+panelHeight > $(window).height()) {
                var panelTop = top-5-$(obj.selectorListPanel).height();
                obj.selectorListPanel.style.top = panelTop+'px';
                obj.selectorListPanel.style.boxShadow= '1px -1px 3px rgba(1, 1, 1, 0.77)';
            }
            obj.selectorListPanel.style.display = 'block';
            return obj;
        };

        this.hidePanel = function() {
            obj.selectorListPanel.style.display = 'none';
        }

        this.doFilter = function (key) {
            if(obj.runFilter && obj.filter && obj.filter.constructor == Function) {
                obj.setOptions(obj.options.filter(function (item) {
                    return obj.filter(item, key);
                }), true);
                obj.index = hoverIndex = 0;
                obj.showPanel();
            }
            return obj;
        }

        window.addEventListener('resize', function (ev) {
            if(obj.selectorListPanel.style.display == 'block') {
                obj.showPanel();
            }
        });

        window.addEventListener('scroll', function (ev) {
            if(obj.selectorListPanel.style.display == 'block') {
                obj.showPanel();
            }
        });

        this.setOptions(obj.options);
    }

</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/u012681635/article/details/79288351
今日推荐