完成iview的下拉select既可以编辑内容又可以选择下拉选项的功能(借助iview的自动完成组件)
最近在使用iview重构老项目页面代码的时候,发现老项目有部分下拉框既可以编辑又可以选择下拉框自带的内容,找了找iview的select组件,发现并没有一个类似的功能。
最接近我的需求的,可能是设置select的filterable属性开启搜索模式,但是每次输入新的内容,鼠标一离开不是被清空,就是选中之前选择的一项,故放弃。
后来又看到iview4.0的版本加了一个allow-create属性,拿给老大看了下,他觉得太麻烦了,不够简洁,首先是必须输完自定义的内容后,一定要点下图的箭头或者按回车,才能将内容加到列表。
另外就是觉得一定要把自定义的内容加到列表中,总觉得不舒服(不是我觉得啊),因此放弃。
对select抱有一丝希望的试了试,出了很多问题,最后放弃了用select组件来做。
后边使用select也实现了该功能,可以查看我下一篇随笔: https://www.cnblogs.com/mayiaction/p/12066923.html
后边发现 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,效果如下:
如果有什么疑问,欢迎留言!