js在前端实现一个下拉搜索的功能
searchableSelect.js
(function($){
// a case insensitive jQuery :contains selector
$.expr[":"].searchableSelectContains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
/*$.expr[":"].searchableSelectContains = function(obj,index,meta){
return $(obj).text().toUpperCase().indexOf(meta[3].toUpperCase()) >= 0;
};*/
$.searchableSelect = function(element, options) {
this.element = element;
this.options = options || {};
this.init();
var _this = this;
this.searchableElement.click(function(event){
// event.stopPropagation();
_this.show();
}).on('keydown', function(event){
if (event.which === 13 || event.which === 40 || event.which == 38){
event.preventDefault();
_this.show();
}
});
$(document).on('click', null, function(event){
if(_this.searchableElement.has($(event.target)).length === 0)
_this.hide();
});
this.input.on('keydown', function(event){
event.stopPropagation();
if(event.which === 13){ //enter
event.preventDefault();
_this.selectCurrentHoverItem();
_this.hide();
} else if (event.which == 27) { //ese
_this.hide();
} else if (event.which == 40) { //down
_this.hoverNextItem();
} else if (event.which == 38) { //up
_this.hoverPreviousItem();
}
}).on('keyup', function(event){
if(event.which != 13 && event.which != 27 && event.which != 38 && event.which != 40)
_this.filter();
})
}
var $sS = $.searchableSelect;
$sS.fn = $sS.prototype = {
version: '0.0.1'
};
$sS.fn.extend = $sS.extend = $.extend;
$sS.fn.extend({
init: function(){
var _this = this;
this.element.hide();
this.searchableElement = $('<div tabindex="0" class="searchable-select"></div>');
this.holder = $('<div class="searchable-select-holder"></div>');
this.dropdown = $('<div class="searchable-select-dropdown searchable-select-hide"></div>');
this.input = $('<input type="text" class="searchable-select-input" />');
this.items = $('<div class="searchable-select-items"></div>');
this.caret = $('<span class="searchable-select-caret"></span>');
this.scrollPart = $('<div class="searchable-scroll"></div>');
this.hasPrivious = $('<div class="searchable-has-privious">...</div>');
this.hasNext = $('<div class="searchable-has-next">...</div>');
this.hasNext.on('mouseenter', function(){
_this.hasNextTimer = null;
var f = function(){
var scrollTop = _this.items.scrollTop();
_this.items.scrollTop(scrollTop + 20);
_this.hasNextTimer = setTimeout(f, 50);
}
f();
}).on('mouseleave', function(event) {
clearTimeout(_this.hasNextTimer);
});
this.hasPrivious.on('mouseenter', function(){
_this.hasPriviousTimer = null;
var f = function(){
var scrollTop = _this.items.scrollTop();
_this.items.scrollTop(scrollTop - 20);
_this.hasPriviousTimer = setTimeout(f, 50);
}
f();
}).on('mouseleave', function(event) {
clearTimeout(_this.hasPriviousTimer);
});
this.dropdown.append(this.input);
this.dropdown.append(this.scrollPart);
this.scrollPart.append(this.hasPrivious);
this.scrollPart.append(this.items);
this.scrollPart.append(this.hasNext);
this.searchableElement.append(this.caret);
this.searchableElement.append(this.holder);
this.searchableElement.append(this.dropdown);
this.element.after(this.searchableElement);
this.buildItems();
this.setPriviousAndNextVisibility();
},
filter: function(){
var text = this.input.val();
this.items.find('.searchable-select-item').addClass('searchable-select-hide');
if(text != ''){
this.items.find('.searchable-select-item:searchableSelectContains('+text+')').removeClass('searchable-select-hide');
}else{
this.items.find('.searchable-select-item').removeClass('searchable-select-hide');
}
if(this.currentSelectedItem.hasClass('searchable-select-hide') && this.items.find('.searchable-select-item:not(.searchable-select-hide)').length > 0){
this.hoverFirstNotHideItem();
}
this.setPriviousAndNextVisibility();
},
hoverFirstNotHideItem: function(){
this.hoverItem(this.items.find('.searchable-select-item:not(.searchable-select-hide)').first());
},
selectCurrentHoverItem: function(){
if(!this.currentHoverItem.hasClass('searchable-select-hide'))
this.selectItem(this.currentHoverItem);
},
hoverPreviousItem: function(){
if(!this.hasCurrentHoverItem())
this.hoverFirstNotHideItem();
else{
var prevItem = this.currentHoverItem.prevAll('.searchable-select-item:not(.searchable-select-hide):first')
if(prevItem.length > 0)
this.hoverItem(prevItem);
}
},
hoverNextItem: function(){
if(!this.hasCurrentHoverItem())
this.hoverFirstNotHideItem();
else{
var nextItem = this.currentHoverItem.nextAll('.searchable-select-item:not(.searchable-select-hide):first')
if(nextItem.length > 0)
this.hoverItem(nextItem);
}
},
buildItems: function(){
var _this = this;
this.element.find('option').each(function(){
var item = $('<div class="searchable-select-item" data-value="'+$(this).attr('value')+'">'+$(this).text()+'</div>');
if(this.selected){
_this.selectItem(item);
_this.hoverItem(item);
}
item.on('mouseenter', function(){
$(this).addClass('hover');
}).on('mouseleave', function(){
$(this).removeClass('hover');
}).click(function(event){
event.stopPropagation();
_this.selectItem($(this));
_this.hide();
});
_this.items.append(item);
});
this.items.on('scroll', function(){
_this.setPriviousAndNextVisibility();
})
},
show: function(){
this.dropdown.removeClass('searchable-select-hide');
this.input.focus();
this.status = 'show';
this.setPriviousAndNextVisibility();
this.dropdown.css('z-index', 100); //打开下拉列表时调高z-index层级
},
hide: function(){
if(!(this.status === 'show'))
return;
if(this.items.find(':not(.searchable-select-hide)').length === 0)
this.input.val('');
this.dropdown.addClass('searchable-select-hide');
this.searchableElement.trigger('focus');
this.status = 'hide';
this.dropdown.css('z-index', 1); //关闭下拉列表时恢复z-index层级
},
hasCurrentSelectedItem: function(){
return this.currentSelectedItem && this.currentSelectedItem.length > 0;
},
selectItem: function(item){
if(this.hasCurrentSelectedItem())
this.currentSelectedItem.removeClass('selected');
this.currentSelectedItem = item;
item.addClass('selected');
this.hoverItem(item);
this.holder.text(item.text());
var value = item.data('value');
this.holder.data('value', value);
this.element.val(value);
if(this.options.afterSelectItem){
this.options.afterSelectItem.apply(this);
}
},
hasCurrentHoverItem: function(){
return this.currentHoverItem && this.currentHoverItem.length > 0;
},
hoverItem: function(item){
if(this.hasCurrentHoverItem())
this.currentHoverItem.removeClass('hover');
if(item.outerHeight() + item.position().top > this.items.height())
this.items.scrollTop(this.items.scrollTop() + item.outerHeight() + item.position().top - this.items.height());
else if(item.position().top < 0)
this.items.scrollTop(this.items.scrollTop() + item.position().top);
this.currentHoverItem = item;
item.addClass('hover');
},
setPriviousAndNextVisibility: function(){
if(this.items.scrollTop() === 0){
this.hasPrivious.addClass('searchable-select-hide');
this.scrollPart.removeClass('has-privious');
} else {
this.hasPrivious.removeClass('searchable-select-hide');
this.scrollPart.addClass('has-privious');
}
if(this.items.scrollTop() + this.items.innerHeight() >= this.items[0].scrollHeight){
this.hasNext.addClass('searchable-select-hide');
this.scrollPart.removeClass('has-next');
} else {
this.hasNext.removeClass('searchable-select-hide');
this.scrollPart.addClass('has-next');
}
}
});
$.fn.searchableSelect = function(options){
this.each(function(){
var sS = new $sS($(this), options);
});
return this;
};
})(jQuery);
searchableSelect.css
/* select */ .searchable-select-hide { display: none; } .searchable-select { display: inline-block; min-width: 100%; font-size: 14px; line-height: 1.428571429; color: #555; vertical-align: middle; position: relative; outline: none; z-index: 9 } .searchable-select-holder{ padding: 0 10px; background-color: #fff; background-image: none; border: 1px solid #d9d9d9; min-height: 36px; line-height: 36px; box-sizing: border-box; -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; } .searchable-select-caret { position: absolute; width: 0; height: 0; box-sizing: border-box; border-color: #a0a0a0 transparent transparent transparent; top: 5px; bottom: 0; border-style: solid; border-width: 5px; margin: auto; right: 10px; } .searchable-select-dropdown { position: absolute; background-color: #fff; border: 1px solid #ccc; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; padding: 4px; border-top: none; top: 28px; left: 0; right: 0; } .searchable-select-input { margin-top: 5px; border: 1px solid #ccc; outline: none; padding: 4px; width: 100%; box-sizing: border-box; width: 100%; } .searchable-scroll { margin-top: 4px; position: relative; } .searchable-scroll.has-privious { padding-top: 16px; } .searchable-scroll.has-next { padding-bottom: 16px; } .searchable-has-privious { top: 0; } .searchable-has-next { bottom: 0; } .searchable-has-privious, .searchable-has-next { height: 16px; left: 0; right: 0; position: absolute; text-align: center; z-index: 10; background-color: white; line-height: 8px; cursor: pointer; } .searchable-select-items { max-height: 400px; overflow-y: scroll; position: relative; } .searchable-select-items::-webkit-scrollbar { display: none; } .searchable-select-item { padding: 5px 5px; cursor: pointer; min-height: 30px; box-sizing: border-box; transition: all 1s ease 0s; } .searchable-select-item.selected, .searchable-select-item.hover { background: #3f86d8; color: white; } /* select */
引入css文件
<link rel="stylesheet" href="{% static 'css/selectSearch/searchableSelect.css' %}" type="text/css" />
引入js文件
<script type="text/javascript" src="{% static 'js/selectSearch/searchableSelect.js' %}"></script>
html
<label class="col-sm-2 control-label">选项1:</label> <div class="col-md-4"> <select id="dep_onwer" name="dep_onwer" class="selectpicker show-tick form-control" data-live-search="true" title="请选择"> </select> </div> <label class="col-sm-2 control-label">选项2:</label> <div class="col-md-4"> <select id="operation_owner" name="operation_owner" class="selectpicker show-tick form-control" data-live-search="true"> </select> </div>
选项1。js
// 页面加载时,获取列表1 $(document).ready(function(){ $ajax({ url: '', data: {}, type: "GET", success: function (data) { if (data.result == false) { } else{ // 赋值给下拉框 {#console.log(data.message)#} var dept = document.getElementById("dep_onwer"); //dep_onwer是select的id标识 var init_op = new Option("--请选择--", 0); dept.options.add(init_op); for(i=0; i<data.message.length; i++){ var op = new Option(data.message[i]['name'], data.message[i]['id']); dept.options.add(op); } $('#dep_onwer').searchableSelect(); } } }); });
选项2。 js
$("#dep_onwer").change(function(){
var dep_onwer_id=$("#dep_onwer option:selected");
console.log(dep_onwer_id.val())
simple_ajax({
url: '',
data: {
"id": dep_onwer_id.val()
},
type: "GET",
success: function (data) {
if (data.result == false) {
alert(data.message);
} else{
$("#operation_owner + div").remove(); //这里是因为跟选项1联动,searchableSelect里会重新将select转化成1个div,如果这里不删除的话,则会出现多个选项2
var owner = document.getElementById("operation_owner"); //operation_owner是select的id标识
owner.options.length = 0 //这里是清除一下选项2的列表,否则来回点选项1,则选项2会一直累加,造成信息错乱
var init_op = new Option("--请选择--", 0);
owner.options.add(init_op);
for(i=0; i<data.message.length; i++){
var op = new Option(data.message[i]['name'], data.message[i]['id']);
owner.options.add(op);
}
$('#operation_owner').searchableSelect();
}
},
});
});
在这里值得一提的地方是,
searchableSelect.js不支持onchange事件,需要在原js文件里的selectItem函数里加上这个方法:this.element.trigger('change');
大功告成
python 中文名:蟒蛇,设计者:Guido van Rossum

浙公网安备 33010602011771号