完成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="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,效果如下:

 如果有什么疑问,欢迎留言!

原文地址:https://www.cnblogs.com/mayiaction/p/12030504.html