最近在使用iview重构老项目页面代码的时候,发现老项目有部分下拉框既可以编辑又可以选择下拉框自带的内容,找了找iview的select组件,发现并没有一个类似的功能。
最接近我的需求的,可能是设置select的filterable属性开启搜索模式,但是每次输入新的内容,鼠标一离开不是被清空,就是选中之前选择的一项,故放弃。
后来又看到iview4.0的版本加了一个allow-create属性,拿给老大看了下,他觉得太麻烦了,不够简洁,首先是必须输完自定义的内容后,一定要点下图的箭头或者按回车,才能将内容加到列表。
另外就是觉得一定要把自定义的内容加到列表中,总觉得不舒服(不是我觉得啊),因此放弃。
对select抱有一丝希望的试了试,出了很多问题,最后放弃了用select组件来做。
后边使用select也实现了该功能,可以查看我下一篇随笔:
后边发现 auto-complete 组件很简洁,在其基础上做了一些改动,最终完成了这个要求,由于考虑到了模糊查询的功能,由于做法的限制,抛弃了iview该组件自带的模糊搜索,所以代码复杂了点。
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="http://unpkg.com/iview/dist/styles/iview.css">
<script type="text/javascript" src="http://vuejs.org/js/vue.min.js"></script>
<script type="text/javascript" src="http://unpkg.com/iview/dist/iview.min.js"></script>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style type="text/css">
#app{padding: 32px;}
[myfocus]{
color: #2d8cf0;
background: #f3f3f3;
}
</style>
</head>
<body>
<div id="app">
<auto-complete
ref = "test"
v-model="nowLabel"
@on-change="changeSel"
@on-select="selectSel"
style="width:200px" icon="ios-arrow-down" >
<i-Option v-for="option in selArr" :value="option.label+'|'+option.value" :key="option.value" >
<span >{{option.label}}</span>
</i-Option>
</auto-complete>
</div>
</body>
<script type="text/javascript">
window.vm = new Vue({
el: '#app',
data: {
nowLabel: '', //存储输入框中显示的内容
nowSel: undefined, //存储需要提交给后台的value
lastLabel: '', //存储上一次输入的内容
selArr:[], //存储select下拉框绑定的列表
isSel:false, ////由于选中和输入内容都会触发onchange,设置此变量进行区分两种情况
//存储页面的原始列表
prevArr:[
{
value:'n',
label:'NewYork'
},
{
value:'l',
label:'London'
},
{
value:'s',
label:'Sydney'
},
{
value:'o',
label:'Ottawa'
},
{
value:'p',
label:'Paris'
},
{
value: 'c',
label: 'Canberra'
}
]
},
created:function(){
this.selArr = this.prevArr; //页面初次加载,下拉列表就是原始列表
},
methods: {
filterMethod:function(value,arr) {
var newArr = [];
for(var i=0;i<arr.length;i++){
if(arr[i].label.toUpperCase().indexOf(value.toUpperCase()) !== -1){
//模糊查询到了,塞入新数组
newArr.push(arr[i]);
}
}
this.selArr = newArr;
},
changeSel:function(){
//更改事件
var that = this;
if(that.isSel){
//如果输入框的改变是选中内容引发的,就什么也不做,同时重新初始化标识,为了解决选中同一内容两次引发的bug
that.isSel = false;
return false;
}
var input = that.nowLabel; //获取输入框输入的内容
that.nowSel = input;
that.clearSelCss(that,"test");
//将输入内容与上一次的输入内容比对上一次输入内容,判断是到初始化列表中查还是从上次查询结果列表查
if(input == null || input == undefined || input == ""){
//输入内容是空,显示原始列表
that.selArr = that.prevArr;
}else if(input.indexOf(that.lastLabel)==0){
//此次输入内容是上次输入内容的开头,不需要到原始列表查,只要到上次查询结果中查
that.filterMethod(input,that.selArr);
}else{
//其他情况到原始列表中查
that.filterMethod(input,that.prevArr);
}
this.lastLabel = input;
},
selectSel:function(val){
let that = this;
//选中事件
that.isSel = true;
var label = val.split("|")[0];
that.nowSel = val.split("|")[1];
Vue.nextTick(function () {
that.nowLabel = label;
that.clearSelCss(that,"test");
var focusItem = $(that.$refs.test.$el).find(".ivu-select-item-focus");
//定义一个属性,用于给选中项设置样式,之所以不设置class,是因为iview会将class替换掉
focusItem.attr("myfocus","myfocus");
});
},
clearSelCss:function(that,ref){
//清除掉已经被选中的项的css
var lastSel = $(that.$refs[ref].$el).find("[myfocus]");
lastSel.removeAttr("myfocus");
}
}
})
</script>
</html>
效果如下,当选中了列表中的内容的时候,需要提交给后台的是选中项的value,而不是label
当自己输入内容的时候,由于并不确定value的值,就认为输入框中的内容就是value,效果如下:
如果有什么疑问,欢迎留言!