基于jquery的可查询多级select控件(可记录历史选择)
一、功能和使用
公司有功能需求,还要一条代码引入的控件,网上找完全符合的控件比较难,寻找所花的时间还不如自己写一个,所以找个空闲时间自己写了一个
控件功能:1、可手动输入查询,也可点击下拉框查询,
2、输入时实时定位到下拉框,enter补全
3、可多级查询(目前是写到二级)
4、localStorage存储历史记录
控件使用:引入相应的js和css文件,需要控件的html中加一个div
<div id="multiple_select" class="multiple-select-container"></div>
js里引入控件
$("#multiple_select").multiSelect({ type:'2',//可选择几级数据 data:data.list,
noneSelectedText: '请选择',
field:['provence','city','name'] //option字段,【一级字段,二级字段,显示字段】 });
二、代码
HTML
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>树形控件</title> <link rel="stylesheet" type="text/css" href="./multiSelect.css" /> </head> <body style="padding:100px;"> <div id="multiple_select" class="multiple-select-container"></div> <script src="plugins/jquery-1.10.2.js"></script> <script src="./multiSelect.js"></script> <script> $(function(){ //测试用的数据 var data = { list:[{ provence:"湖北", city:[{name:"武汉",code:1}, {name:"仙桃",code:2},{name:"天门",code:3}] }, { provence:"河北", city:[{name:"石家庄",code:1}, {name:"邯郸",code:2},{name:"唐山",code:3}] },{ provence:"湖南", city:[{name:"郴州",code:1}, {name:"岳阳",code:2},{name:"长沙",code:3}] }] } //控件引用 $("#multiple_select").multiSelect({ type:'2',//可选择几级数据 data:data.list, field:['provence','city','name'] , //option字段,第一个是1级展示数据的字段,第二个是二级数据字段,第三个是显示字段 record: true, //是否需要历史记录功能,只展示最近使用的前三条数据 noneSelectedText : '', //未选择时展示数据 }); }); </script> </body> </html>
CSS
* { padding: 0; margin: 0; } ul li { list-style: none; } /*fontclass*/ @font-face { font-family: "iconfont"; src: url('iconfont.eot?t=1537237853618'); /* IE9*/ src: url('iconfont.eot?t=1537237853618#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAVYAAsAAAAACCQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8hUioY21hcAAAAYAAAABoAAABquZlt9xnbHlmAAAB6AAAAV8AAAG8iReSsmhlYWQAAANIAAAALAAAADYSq0zoaGhlYQAAA3QAAAAcAAAAJAfeA4ZobXR4AAADkAAAAA4AAAAUFAAAAGxvY2EAAAOgAAAADAAAAAwA2AFKbWF4cAAAA6wAAAAfAAAAIAESADtuYW1lAAADzAAAAUUAAAJtPlT+fXBvc3QAAAUUAAAAQgAAAFf+vnWeeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGBye8T/bxtzwv4EhhrmBoQEozAiSAwDr4gyoeJztkcENgCAMRV8FjTEmhj0cwKPDeHI/GalrYFscw08e+f1pORRgBJKxGxnkRnBdlkrkiSXyzGH1bGcA3bRobe1zj7uQRMccr4nNWq9M/FrjPr8q+9464UvHN65Px39Fa4fhBcRnF9R4nE2QP0/CQBiH732vtrRXwcT+wRBabWKLS4lt02646IgTwbBRZhkYlX4BExNC4uTiqFE+BHwL+DBePFoTveF+l8tzz+/yEiRi0RHuCCMBIVAHxQG7B1kIx5Yhe11QZM9PriDwkzRyIUsjy2gASssNpZvlci1Ja4dZbX1eMMfUikIzHVbM9bbFCtxK64oQO4+ZuJvPBcuK4t9ZlJZ/eMUJMQjJVLCi1A9EYeDLCsgORNknDGCku01o8JfaAbITxhcqNF19BXf8i9muDvc1CpKk8oXA9D/neO9U0fdkywbbsq00gzQET6FDvuLvpVO8LZ0wK5044B8w3EtFWSmFWSmlpXNGL8kROSMhIedeiEkPIweNOlKvjoaDUQ+TEEHuQjUwMUR4u3nMoyh/fKriOpv0O53+ZFoFPByynWa22FYznuOKisf7iHHcuc1/sWnev/g+BbZlLVPbsZbxAzYBVaMAeJxjYGRgYADikyacs+P5bb4ycLMwgMD1Yy2xyDQLA7MhkOJgYALxAArgCJB4nGNgZGBgbvjfwBDDwgACQJKRARWwAgBHCwJueJxjYWBgYEHDAAEEABUAAAAAAAAAQgBsAJYA3nicY2BkYGBgZdBnYGYAASYg5gJCBob/YD4DAA2tAU4AeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicY2BigAAuBuyAlZGJkZmRhZGVkY2BJzknvzhVNzmzKDknlSOxqCi/XLe0gAvCSMkvz2MrTk0sSs5gYAAATLsOxwAA') format('woff'), url('iconfont.ttf?t=1537237853618') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('iconfont.svg?t=1537237853618#iconfont') format('svg'); /* iOS 4.1- */ } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-close-circle:before { content: "\e611"; } .icon-arrow-up:before { content: "\e6b6"; } .icon-arrow-down:before { content: "\e6b5"; } .icon-search:before { content: "\e60f"; } /*fontclass end*/ .multiple-select-container { width: 166px; height: 34px; line-height: 34px; position: relative; display: inline-block; vertical-align: middle; } .multiple-select-container .select-inputbox { width: 100%; height: 40px; line-height: 40px; padding: 0 9px; position: relative; box-sizing: border-box; } .multiple-select-container .select-input, .multiple-select-container .select-button { width: 100%; height: 100%; outline: none; box-sizing: border-box; background: #FFF; } .multiple-select-container .select-input { padding: 5px 22px; border-radius: 2px; border: 1px solid #CFCFCF; height: 28px; } .multiple-select-container .select-button { padding: 5px 25px 5px 12px; border: 1px solid #CFCFCF; border-radius: 4px; text-align: left; display: flex; justify-content: space-between; } .multiple-select-container .select-button span { display: inline-block; height: 100%; line-height: 22px; } .multiple-select-container .selected-data { width: 80%; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .multiple-select-container .input-isfold { float: right; cursor: pointer; margin-right: -16px; font-size: 12px; } .multiple-select-container .input-search, .multiple-select-container .input-close { position: absolute; cursor: pointer; top: 50%; transform: translateY(-50%); display: inline-block; height: 16px; line-height: 16px; font-size: 18px; } .multiple-select-container .input-close { left: calc(95% - 22px); width: 12px; color: #7B7B7B; display: none; } .multiple-select-container .input-search { color: #ADADAD; left: 12px; width: 16px; } .multiple-select-container .select-options-box { width: 100%; display: none; position: absolute; border: 1px solid #c2cad8; z-index: 999999; background: #fff; height: 300px; overflow-y: auto; } .multiple-select-container .options-container { width: 100%; height: auto; } .multiple-select-container .options-record, .multiple-select-container .optionslist { font-size: 14px; width: 100%; box-sizing: border-box; padding: 0 9px; text-align: left; } .multiple-select-container .options-record { color: #999; height: 34px; line-height: 34px; } .multiple-select-container .optionslist { cursor: pointer; height: 26px; line-height: 26px; } .multiple-select-container .optionslist:hover { background: #DEEDFF; } .multiple-select-container .options-one { font-size: 16px; } .multiple-select-container .options-two { width: 100%; font-size: 14px; } .multiple-select-container .options-two li { padding-left: 15px; } .multiple-select-container .options-isfold { float: right; display: inline-block; width: 16px; } .multiple-select-container .active-border { border: 1px solid #009BE1; } .multiple-select-container .background-color { background: #ECECEC!important; } .multiple-select-container .border-bottom { border-bottom: 2px solid #D4D4D4; } ::-webkit-scrollbar { width: 5px; height: 5px; } ::-webkit-scrollbar-thumb { background: #DCDCDC; border-radius: 8px; }
JS
; (function($, window, document) { var pluginName = 'multiSelect', defaults = { type: '1', //select层级onetwo data: [], //数据 field: [], //数据字段名 record: false, //是否记录最近使用的三条数据 chooselast: true, //是否在初始化后自动选择最近使用的选项,record必须为true noneSelectedText: '', //未选择时显示文字 isfoldFirst: false, //是否默认展开二级目录 disabled: '', //是否禁用 hasinput: true, //是否显示搜索框 id: '', //id字段名 allselect: '', //全选或者不选择 queryFun: function() {}, //搜索方法 }; function MultiSelect(element, options) { this.element = element; this.settings = $.extend({}, defaults, options); this.init(); } MultiSelect.prototype = { //初始化弹出框 init: function() { var that = this, element = this.element; that.create(element); that.triggerlist(element); }, //创建select框 create: function(element) { var that = this, $this = $(element), noneSelectedText = that.settings.noneSelectedText, selectElement = '<button name="selectinput" class="select-button">' + '<span id="selected_data" class="selected-data">' + noneSelectedText + '</span><span class="input-isfold iconfont icon-arrow-down"></span></button>' + '<div class="select-options-box" id="select_options_box"></div>'; $this.append(selectElement); var $options_box = $this.find('#select_options_box'); $this.on({ 'hideoptions': function(e) { $options_box.fadeOut(); $this.find('.input-isfold').toggleClass('icon-arrow-down icon-arrow-up'); }, 'showoptions': function(e) { $options_box.fadeIn(); $this.find('.input-isfold').toggleClass('icon-arrow-down icon-arrow-up'); } }); that.initOption(element); }, //初始化列表 initOption: function(element) { var that = this, $this = $(element), $options_box = $this.find('#select_options_box'); var $options = that.parseOptions(); $options_box.html($options); }, //解析并处理options数据 parseOptions: function() { var that = this, type = that.settings.type, field = that.settings.field, one = field[0], two = field[1], data = that.settings.data, allselect = that.settings.allselect, hasinput = that.settings.hasinput, disabled = that.settings.disabled, twolist = '', optionsTwo = [], record = that.settings.record, noneSelectedText = that.settings.noneSelectedText, options = ''; var recordColumn = JSON.parse(window.localStorage.getItem("recordInfo")) ? JSON.parse(window.localStorage.getItem("recordInfo")) : []; console.log("recordColumn" + recordColumn); options += '<div class="options-container">'; if (record && recordColumn.length > 0) { options += '<div class="options-record"><span class="options-data">最近使用</span>' + '</div>'; for (var i = 0; i < recordColumn.length; i++) { if (recordColumn[i] != undefined && JSON.stringify(data).indexOf(JSON.stringify(recordColumn[i].id)) >= 0) { options += '<div class="optionslist" disabled="' + disabled + '" id="' + recordColumn[i].id + '" data-index=' + recordColumn[i].dataIndex + '">' + '<span class="options-data">' + recordColumn[i][one] + '</span></div>'; } else { recordColumn.splice(i, 1); window.localStorage.setItem("recordInfo", JSON.stringify(recordColumn)); } } } if (noneSelectedText) { options += '<div class="options-record optionslist" id="none_selected_all"><span class="options-data">' + noneSelectedText + '</span></div>'; } if (hasinput) { options += '<div class="select-inputbox"><input type="text" name="selectinput" id="select_input" class="select-input" placeholder="" />' + '<i class="input-search iconfont icon-search"></i>' + '<i class="input-close iconfont icon-close-circle"></i></div>'; } switch (type) { case '1': for (var i in data) { options += '<div class="optionslist" disabled="' + disabled + '" id="' + data[i].id + '" data-index="' + i + '"><span class="options-data">' + data[i][one] + '</span></div>'; } break; case '2': for (var i in data) { twolist = '', optionsTwo = []; var optionsTwo = data[i][two]; for (var j in optionsTwo) { twolist += '<li class="options-container optionslist" disabled="' + disabled + '" id="' + data[i].id + '" data-index="' + i + '" data-twoindex="' + j + '">' + '-- ' + '<span class="options-data">' + optionsTwo[j][field[2]] + '</span></li>'; } options += '<div class="options-one optionslist" disabled="' + disabled + '" id="' + data[i].id + '" data-index="' + i + '">' + '<span class="options-data">' + data[i][one] + '</span><span class="iconfont icon-arrow-up options-isfold"></span>' + '</div>' + '<ul class="options-two">' + twolist + '</ul>'; } break; } options += '</div>'; return options; }, //系列事件 triggerlist: function(element, event) { var that = this, $this = $(element), data = that.settings.data, field = that.settings.field, one = field[0], two = field[1], isfoldFirst = that.settings.isfoldFirst, noneSelectedText = that.settings.noneSelectedText, $options_box = $this.find('#select_options_box'), $isfold = $this.find('.options-isfold'), record = that.settings.record, chooselast = that.settings.chooselast, disabled = that.settings.disabled, $input = $this.find('#select_input'), $selected = $this.find('#selected_data'), $button = $this.find('.select-button'); var recordColumn = JSON.parse(window.localStorage.getItem("recordInfo")) ? JSON.parse(window.localStorage.getItem("recordInfo")) : []; $input.on({ 'input propertychange': function() { that.selectFun(false, false, element); }, 'click': function() { $options_box.show(); return false; } }); $this.find('.input-search').on('click', function(event) { $this.trigger('showoptions', e); that.selectFun(false, false, element); return false; }); $this.find('.input-close').on('click', function(event) { $options_box.show(); $input.val(''); $(this).hide(); return false; }); $button.on('click', function(event) { $(this).addClass('active-border'); $options_box.toggle(); that.selectFun(false, true, element); $this.find('.input-isfold').toggleClass('icon-arrow-down icon-arrow-up'); event.stopPropagation(); }) $isfold.on('click', function(event) { // that.selectFun(false, true, element); $(this).parent().next().toggle(); $(this).toggleClass('icon-arrow-down icon-arrow-up'); $options_box.show(); // $this.trigger('showoptions'); event.stopPropagation(); }) //选择事件 $this.find('.optionslist').on({ 'click': function(event) { if (disabled) return; $button.removeClass('active-border'); $(this).addClass('background-color'); $this.find('.optionslist').removeAttr("selected"); $(this).attr("selected", "selected"); $selected.html($(this).find('.options-data').html()); if ($.isFunction(that.settings.queryFun)) { that.settings.queryFun(); } if ($(this).attr("id") === "none_selected_all") { $button.data("data", null) $selected.html(noneSelectedText); } else { var recordIndex = parseInt($(this).attr("data-index")), twoIndex = parseInt($(this).attr("data-twoindex")), a = {}, b = { dataIndex: recordIndex }; if ($(this).attr("data-twoindex")) { a = data[recordIndex][two][twoIndex]; } else { a = data[recordIndex]; } recordCol = $.extend(a, b); $button.attr("data-index", recordIndex); $button.data("data", a) if (record) { // console.log("recordCol:" + recordCol + " recordColumn:" + JSON.stringify(recordColumn)); var len = recordColumn.length, existIndex = -1; // if (JSON.stringify(recordColumn).indexOf(JSON.stringify(recordCol)) > -1) { for (var i = 0; i < len; i++) { if (recordColumn[i].dataIndex == recordIndex) { existIndex = i; } }; if (existIndex > -1) { recordColumn.splice(existIndex, 1); } // }; recordColumn.unshift(recordCol); len = recordColumn.length; if (len > 3) { recordColumn.splice(3, len - 3); } window.localStorage.setItem("recordInfo", JSON.stringify(recordColumn)); } } // $button.attr("data", a) $this.trigger('hideoptions'); event.stopPropagation(); }, 'mouseover': function() { $(this).css({ 'background': '#DEEDFF' }); }, 'mouseout': function() { $(this).css({ 'background': '#fff' }); } }); $(document).keyup(function(event) { if (event.keyCode === 13&&$input.is(':focus')) {
that.selectFun(true, false, element); if ($.isFunction(that.settings.queryFun)) { that.settings.queryFun(); } } event.stopPropagation(); }); /* $(document).on('click', function(event) { $options_box.hide(); }); */ $(document).on('click', function(event) { var _tar = $button.children(); if (!_tar.is(event.target) && _tar.has(event.target).length === 0) { // Mark 1 $options_box.fadeOut(); $button.removeClass('active-border'); } }); if (chooselast && record && recordColumn.length > 0) { $this.find('.optionslist').first().trigger("click"); } if (!isfoldFirst) { $isfold.trigger("click"); } }, // input与select同步 selectFun: function(enter, button, element) { //enter为true代表是键盘enter键,button为true代表是select,为false代表是input搜索框 var that = this, $this = $(element), data = that.settings.data, $options_box = $this.find('#select_options_box'), $input = $this.find('#select_input'), options = $this.find('.optionslist'), $selected = $this.find('#selected_data'), optionTop = 0, selectHTML = ''; var optiondata = button ? $selected.html() : $input.val(); if ($input.val()) { $this.find('.input-close').show(); } else { $this.find('.input-close').hide(); } $.each(options, function(i, item) { selectHTML = $(item).find('.options-data').html(); // console.log(selected); if (selectHTML.indexOf(optiondata) >= 0) { // $(item).trigger('hover'); options.removeClass('background-color'); $(item).addClass('background-color'); /*if ($(item).hasClass('options-one')) { optionTop = $(item).position().top; }else{ optionTop = $(item).parent().position().top; }*/ optionTop = $(item).position().top; // console.log(optionTop); $options_box.scrollTop(optionTop); if (enter) { $(item).trigger('click'); } } }); if (optiondata === '') { options.removeClass('background-color'); $options_box.scrollTop(0); } } }; $.fn[pluginName] = function(options) { this.each(function() { if (!$.data(this, "plugin_" + pluginName)) { $.data(this, "plugin_" + pluginName, new MultiSelect(this, options)); } }); return this; }; //外部获取选中数据 $.fn.extend({ optionSelected: function() { if ($(this).find("button").data("data")) { return $(this).find("button").data("data"); } else { return ""; } }, setOption: function(id) { if (id && id != "" && id.length > 0) { $(this).find("#" + id).trigger('click'); } }, setDisabled: function() { $(this).find("button").css("background-color", "#ccc"); $(this).css("pointer-events", "none"); $(this).parent().css("cursor", "no-drop"); }, }); })(jQuery, window, document)