【Bootstrap】bootstrap-select2下拉菜单插件
这次开发了个⼩TRS系统,虽然是很⼩,但是作为初⼼者,第⼀次⽤到了很多看起来洋⽓使⽤起来有相对简单的各种前端(主要是和bootstrap配合使⽤)组件。包括bootstrap-select2,bootstrap-datetimepicker,bootstrap-fileinput等。本⽂就旨在记录⼀些这些组件相关的内容
【bootstrap-select2】
官⽅⽂档:【/options】
这个组件主要⽤于优化<select>等页⾯组件。⽐如我们想要在下拉菜单的顶部加上⼀个搜索框⽀持我们对选项进⾏搜索,抑或是在多选下拉菜单中我们要有那种类似于tag形式的表现,⽤这个组件就很好了。⾸先是这个组件需要在页⾯中进⾏引⼊的⽂件:
<link href="{% static 'select2/dist/css/select2.min.css' %}" rel="stylesheet" />
<script src="{% static 'select2/dist/js/select2.min.js' %}"></script>
<script src="{% static 'select2/dist/js/i18n/zh-CN.js' %}"></script>
zh-CN.js是语⾔翻译⽂件,需要注意引⼊必须在select2.min.js后⾯,否则会报错。这⼀点也适⽤于绝⼤多数⽀持国际化显⽰的组件。
当然因为是bootstrap的组件,⾃然是不能少bootstrap的js和css以及⽀持bootstrap的jquery了,这个就不写出来了。
■ 带静态搜索框的下拉菜单
所谓静态搜索框,就是指这个下拉菜单⾥所有的option都是在页⾯渲染时就已经固化好了的,⽤这个搜索框进⾏搜索时不会动态发请求到后台去取数据。这个搜索框的HTML可以这么写:
<select id="static_dropdown" class="form-control">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
这就是⼀个普通的select,只不过需要有form-control这个class和⼀个⽤于后续表⽰⽤的id。
然后在js中这么写:
$('#static_dropdown').select2({
language: 'zh-CN',
width: '100%',
placeholder: '请选择',
minimumInputLength: 10
});
利⽤前端组件⼀个⾮常重要的内容就是把握初始化时各个初始化参数的含义。通过对不同参数发出调整来搞出⼀个符合⾃⼰需求的组件。
这⾥⽤到的四个参数,language显⽽易见是国际化显⽰⽤的。width指出了这个select的宽度,placeholder就是,minimunInputLength指出了在搜索时⾄少要输⼊多少字符才会给出响应
的搜索结果。如果待选项不是太多的话尽量不要设置过⼤的值,像⽰例的10,我觉得是很⼤的⼀个值了。。
下⾯也会零散性地给出⼀些参数说明:
selectOnClose 当设置成true时,当收起菜单时的⾼亮项会⾃动被选择,如果是false则不会⾃动选择。
dropdownParent 可以指定下拉菜单在html代码中的位置。默认情况下,下拉菜单都是被append到body中,并且被设置成position:absolute,且位置在select的下⽅。⽽设置这个参数⽐如dropdownParent: $('#myModal'),就可以将下拉菜单放⼊⼀个指定的容器中。
tags 把tags设置成true了之后,在搜索时即便没有搜索到相关内容,也会把你输⼊的内容当成⼀个可选项。之所以被称为tags,就是因为tags这个东西不⼀定要都是既存的,可以有⾮既存⽽我们⾃⼰添加的情况。
placeholder 如果值是⼀个字符串那么就是⼀个简单的placeholder,如果换成⼀个对象也可以,即为菜单添加⼀个默认的选项。⽐如placeholder: {id:-1,text:'--请选择--'}
tokenSeparators 可以设置成⼀个包含各种字符的列表如[',',' '],常和tags以及多选菜单配合使⽤。即⾃⼰输⼊时,输⼊逗号或空格(看你这个参数设置的情况)时认为是⼀个tag的终结,就把前⾯的内容作
为⼀个新tag添加到多选框⾥⾯。
createTag 这个参数的值也是⼀个函数对象。这个函数接受⼀个参数param,其结构是这样的
我们主要关注term这⼀项的值,我们可以在createTag指定的函数中对term进⾏⼀些逻辑判断和处理,然后返回⼀些结果来让添加标签的过程更加智能化⼀些。⽐如:
$('#testselect').select2({
createTag: function(param){
var term = $.);
if (term.indexOf('@') == -1){
return null;
}
else {
var id = term.split('@')[0];
var text = term.split('@')[1];
return {id:id,text:text};
}
}
});
在⽤户输⼊⾃定义的tag的时候可以检查存不存在@,如果不就不允许其增加这个tag,如果存在则@前⾯的部分作为value,后⾯的部分作为<option>的text,加⼊⼀个新的tag。
minimunResultsForSearch 通常这个参数设置成⼀个整数,当option的待选数量⼤于这数字时才显⽰搜索框。当把这个参数设置为Infinity时将默认不显⽰搜索框即禁⽤搜索框。这样select就变成了⼀个simple的select了。
maximumSelectionLength 若是多选框,设置最多可以选择⼏项
另外,可以在select和option中引⼊⼀层optgroup标签并设置其label属性。optgroup可以为所有选项划分出合适的组分并且显⽰以label 的标签。将option的disabled设置为disabled还可以禁⽌选择某⼀个选项。
●带有图⽚的下拉菜单
上⾯的说明,得到的下拉菜单都是纯⽂字的。其实select2⽀持我们传递图⽚进去作为每个选项的⼀个修饰。这⾥就要⽤到templateResult这个参数。
⾸先要明确,我们虽然在html上写的是select和option,但是最终经过select2的加⼯呈现出来的是ul和li,每个li⾥⾯是当时option中的内容。在了解这⼀点的基础上,我们的templateResult参数是⼀个函数对象。这个函数对象接受⼀个object(这个object⼋成是select2内部定义的抽象了菜单选项的object)为参数并且返回字符串或jquery对象供select2渲染成菜单选项。简单来说,就是select2会对所有选项进⾏⼀个遍历,依次执⾏⼀下这个函数然后按照我们定义的⽅式渲染出我们想要的菜单选项的样式和内容。⽐如下⾯这样:
templateResult: function(row){
return $('<span><img class="img-flag" src="/static/img/'+row.id+'.png">'++'</span>');
}
上⾯这个函数有点绕,简单来说就是可以把/static/img/<;每个option设置好的value值>.png作为标识图⽚放在option的旁边。如果在这个函数中断点看下row的具体情况的话,就可以看到其实这个row的结构是这样的:
Object { selected: false, disabled: false, text: "张三", id: "10001", title: "", _resultId: "select2-addTrainSpeaker-result-5o5i-10001", element: option }
也就是说我们的option的value在这⾥是id,option的字符串在这⾥是text,这样就可以根据value和字符串来定制了。顺便⼀提,上⾯的函数中return要加上$()是因为不这样返回的默认是字符串,也就是每⼀项的内容都会变成<span>xxxx的样⼦⽽不是html内容。所以返回jquery对象⽐较靠谱。
在编写templateResult函数的时候,还要注意对loading状态的处理。当打开下拉列表时,最先进⼊这个函数的应该是loading状态的对象,此时row没有id属性,当时有loading:true属性,如果此时不返回当前的(正在加载中之类的提⽰⽂字)的话,渲染有可能就停⽌在这步。所以⼀般⽽⾔可以在templateResult函数⾥写上if(row.loading){;}之类的逻辑。
■ tag形式的多选框
所谓tag形式的多选框就是指这种:
这个看起来⽐较复杂,其实也通过select2实现也⽐较⽅便。html可以这么写:
<button class="close" type="button" id="multiple_all">+</button>
<select class="form-control" id="multiple_choice" multiple="multiple">
<option value="1">a</option>
<option value="2">b</option>
<option value="3">c</option>
</select>
然后在js中这样写:
var multiple = $('#multiple_choice').select2({
placeholder: '请选择',
allowClear: true
});
$('#multiple_all').click(function(event){
event.preventDefault();
var res = [];
$(this).next('select').find('option').each(function(i,ele){
res.push($(ele).val())
});
$(multiple).val(res).trigger('change');
});
第⼀部分很好理解,和上⾯的下拉菜单⼀样,也是初始化。只是这个初始化返回了⼀个jquery对象,我们先⽤multiple这个变量保存下来。然后当select前⾯的那个按钮被点击时,就是执⾏了第⼆部分代码,是将select中所有选项的值都加⼊到⼀个数组中,然后把这个数组传递给刚才那个multiple对象的val⽅法,再trigger⼀下change事件。这样就可以⾃动地选择所有选项到多选框⾥⾯了。(这部分是我⾃⼰加上去,不是select2要求的)。
可以看出来$(multiple).val(xxx).trigger('change')就是拿来引发多选框被选中值变化的⽅法。如果xxx处填写null那么就是清空多选框了。
关于如何取值,类似的我们可以$('#multiple_choice').val()来取值,得到的应该是⼀个数组。这⾥多提⼀句,如何通过ajax传递数组给后台。直接写⼊ajax⽅法的data字段需要特殊处理过的数组。⽐如我们有数组对象array想要作为参数parti的值通过ajax传递出去的话,那么可以先JSON.stringify(array),得到
的json化的字符串再拿来传递即可。在后台我们只要⽤相关后台的⽅法来解析json格式字符串即可。
■ 编程控制
上⾯提到了如何⼀键清空或全选多选框的选项、这个其实是⼀个select2组件的编程控制。更⼀般地来说我们可以这样给下拉菜单多增加⼀个选项:
var data = {
id: 1,
text: 'test'
};
var newOption = new ,data.id,false,false);
$('#testselect').append(newOption).trigger('change');
如果是选取若⼲个可以传递⼀个数组给val⽅法。如果需要对待加⼊项是否已经存在做出判断的话可以这么做:
if ($('#testselect').find('option[value='+data.id+']').length){
$('#testselect').val(data.id).trigger('change'); //如果已经存在则不添加⽽是选择那⼀项
}
else{
var newOption = new Option(data.,true,true);
$('#testselect').append(newOption).trigger('change');
}
■ 动态搜索下拉菜单
所谓动态,即每次搜索框中数据发⽣变化时,前端会向后台发送ajax请求来获取⼀些数据,把这些数据⽤于填充下拉菜单的内容。实现⽅法是在初始化select2组件的时候加⼊ajax参数,如:
$('#testselect').select2({
ajax : {
url: '/api',
dataType: 'json', //⽐较重要,没有的话返回json数据会⽆法识别,搜索失败
data: function(param){
return {
keyword: ,
searchType: 'public',
page: param.page || 1
}
}
}
})
ajax参数的值是⼀个object,包括url等key。url这个肯定是要有的,指出了ajax请求发往什么地⽅。data参数是可选的,在默认情况下select2发出的请求包含了以下⼏个参数:
term 此时搜索框中的内容
q 和term内容⼀样
_type 通常是query,如果涉及到结果分页时可能不⼀样
page 当有结果分页时有此参数,指出当前分页
*关于分页和page参数:在当前处于默认第⼀页的时候,发送的请求不带page参数,所以⼀般来说我们都会在data参数的函数对象中对page参数做这样⼀个处理: params.page = params.page || 1;来保证第⼀次打开输⼊框时也会给出page=1作为请求参数。
在设置data参数之后,data参数的值是⼀个获取当前搜索框中对象(具体搜索内容是其term参数)并返回⼀个object作为ajax参数的函数对象,我们可以借此来定义⼀些⾃定义的请求参数字段。
需要特别说明的是,这⾥的ajax请求默认是get⽅法,⽬前还没到如何改成post的办法。
因为前端会⾃动对后端传递过来的数据进⾏适应select2组件的渲染,所以其对于数据的格式肯定是有要求的。具体的要求是这样的:
{
results: [
{id: '10001', text: 'Option_1'},
{id: '10002', text: 'Option_2'},
//等等,这部分就是主要的数据
],
pagination: {
more: true
}
}
主要数据部分每个列表项都是⼀个object且包含id和text两个字段分别⽤来填充option标签对应的那两个字段。pagination则是指出了前端会对上送的结果做⼀个分页处理,即⼀次性只在下拉列表中显⽰有限个项,但在最下⽅有⼀个“显⽰更多项”,当滚动条到最下⽅时再⾃动发送请求去调取下⼀个分页的数据。当然,顺利地实现分页需要前端发出的ajax请求中带有param.page这个信息(如上上⾯的代码所⽰),然后后端也要根据上送上来的page的值来进⾏相应数据段的返回。前后端协调了才可以给出⽐较好的分页效果。
上⾯的说明中可以看得出对数据格式要求⽐较严格(results,pagination,id,text等字段都不能⾃定义),为了适应更加多样化的形式的数据,我们可以在ajax参数中再加上⼀个processResults字段:
$('#testselect').select2({
ajax: {
url: '/api',
dataType: 'json',
data: function(param){
return {
kw: ,
page: param.page || 1
};
},
processResults: function(data){
return {
results: data.items
};
}
}
})
上⾯的⽰例虽然有了分页,不过还有个⼩瑕疵,就是即使加载完了所有数据,最下⾯的加载所有数据依然会存在⽽不消失。这个问题可以在前端解决,官⽅⽂档中给出的⽰例是这样的:
processResults: function(data,params){
params.page = params.page || 1;
return {
results: sults,
pagination: {
more: (params.page * 10) < al_count
}
};
}
⾸先,返回的结果中多了⼀个total_count字段,它指出了未分页时结果集的个数。注意是未分页时,即搜索条件不变时不论page是多少这个字段的值是不变的。然后在后端返回中的pagination字段可以去掉了,因为这个字段通过前端的逻辑判断来置true或false,这个条件,就是上⾯写着的当前页⾯*10是否⼩于总条数(也就是⼀次显⽰10条)。若否,表明已经加载到了最后⼀页,此时pagination就可以是false,即不需要再显⽰“加载更多数据”了。
需要额外说⼀下,分页的个数最好要达到5个以上才会有正常的效果。我尝试了⼀次分页只给出两三个结果的时候,前端页⾯会⼀直显⽰在加载更多结果但是没有真的在加载数据
bootstrap 5 ●更多ajax参数
delay 可以在ajax的参数中加上delay,取值单位是毫秒。意思是说当⽤户停⽌输⼊了这么多毫秒之后再发出ajax请求。⽤户每改动⼀个字母就发出⼀次请求显然是⽐较浪费资源的,这么做更加合理⼀些。
■ 设置选择框的默认值
对于静态框,我们可以在⽣成之后通过$(element).val([...]).trigger('change')的办法来为select2渲染出来的东西添加⼀个或⼀些默认选中的值。如果⼀定要在初始化的时候就设置好默认的值那么也可以利⽤placeholder这个初始化参数。正如上⾯所说,如果placeholder是个字符串那么就是普通的placeholder,但如果是个object那么将会是⼀个提⽰默认选择值的东西。
对于有ajax参数的动态选择框有些复杂。我在实践中到了⼀种⽅法。我们知道,构造⼀个动态的选择框是不需要在select标签中添加option的,但是即便我们あえて添加⼀些的话,渲染出来的动态框,我们打开选择框也不会出现那个预设的静态选项。不过它有⼀个⽤,就是可以被val([xxx]).trigger('change')这个操作捕捉到。
也就是说,如果我们想对⼀个动态框预设⼀个或⼏个选中值(通常这些值应该也是我们预期能够通过动态框获取到的值),我们可以⾸先假装它是⼀个静态选项,作为<option>写死到<select>中去,然后再通过val([...]).trigger('change')将这些所谓的静态选项置选中。事实上这些所谓的静态选项并不会出现在选择框中,⽽静态的<option>和val/trigger两者的交集会作为最终被选中的默认值。
⽰例:
<!-- HTML中 -->
<select multiple class="form-control" id="test">
<option value="0">Preselected Value 1</option>
<option value="1">Preselected Value 2</option>
</select>
//js中
$('#test').select2({
ajax: {...} // 构造了⼀个动态的选择框
}).val(['0','1']).trigger('change');
然后页⾯上的这个多选框就是默认选中了Preselected Value1和Preselected Value2两个选项(不管ajax请求发出之后能否真的能获取到这两个选项)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论