vue实现下拉框全选和输入匹配

实际项目中的一个需求:

点击文本框,弹出带有复选框的选项,然后获取选中项的数据,传给后面的一个功能。在文本框输入内容,也会动态的匹配下拉列表,并且列表带有全选功能。

 

朴素的效果图:

 

 

我选择了用vue实现,算是vue的一次练手吧。不会写的地方也百度了一下。

难点有两个,一个是全选。全选不光是点击全选复选框,选项跟着选中或不选中。还包括反向的选择,就是如果把所有选项选中了,那么“全选”也要跟着选中,而有任何一项未选中,那么“全选”则处于未选中状态。也就是说这是个互动的过程。只有做到这点,才是一个好的用户体验。

我是在循环数据的每一项加了一个表示选中状态的值lineCheck。全选和选项的点击分别写。点击全选中,把选项的状态置为和其一致就可以。

点击选项时,利用every方法,只有每一项为真(也就是选中),全选才为真,否则为假(未选中)。 

第二个难点就是输入时的匹配问题,是在computed中写了一个searchLists,下拉列表的for循环也用的这个数据,全选时遍历的也是这个数据。

 

其他tips:

1)表单的操作离不开v-model

2)点击事件加上stop修饰符,阻止冒泡

3)复选框的事件用的change

4)注意用label,这样点击文字也有效果,体验更佳

5)点击页面空白处,隐藏下拉列表

 

总体来说,用户体验做的还是不错的。

贴出完整代码:(没有好看的样式,就是最朴素的效果,毕竟css对于前端人员来说是最最简单的)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>下拉框全选</title>
        <link rel="stylesheet" href="css/this.css" />
    </head>
    <body>
        <div class="m-select-wrap" id="v_app">
            <div class="title">
                <input type="text" placeholder="输入/勾选" v-model="searchLine" @click.stop="showList" @focus="inputFocus">
                <span class="show-list" @click.stop="toggleList"></span>
                <span class="select-con">选中了:{{selectCon}}</span>
            </div>
            <ul v-if="isShow" @click.stop="showList">
                <li>
                    <label><input type="checkbox" v-model="checkAllState" @change="checkAll"> 全选</label>
                </li>
                <li v-for="item in searchLists">
                    <label :id="item.lineId"><input type="checkbox" v-model="item.lineCheck" @change="checkOne(item)"> {{item.lineName}}</label>
                </li>
            </ul>
        </div>

        <script src="js/vue.js"></script>
        <script>
            var lines = [
                {
                    lineId: 'line1',
                    lineName: '数据1',
                    lineCheck: false
                },
                {
                    lineId: 'line2',
                    lineName: '数据2',
                    lineCheck: false
                },
                {
                    lineId: 'line3',
                    lineName: '数据3',
                    lineCheck: false
                },
                {
                    lineId: 'line4',
                    lineName: '数据4',
                    lineCheck: false
                },
                {
                    lineId: 'line5',
                    lineName: '数据5',
                    lineCheck: false
                }                
            ]

            new Vue({
                el: '#v_app',
                data: {
                    //数据
                    lineList: lines,
                    //选项的选中状态
                    checkAllState: false,
                    //选中的数据
                    checkedList: [],
                    //文本框的值
                    searchLine: '',
                    //下拉列表是否显示
                    isShow:false,
                    //选中的内容
                    selectCon:''
                },
                methods: {
                    //全选
                    checkAll: function() {
                        for (var i = 0; i < this.searchLists.length; i++) {
                            this.searchLists[i].lineCheck = this.checkAllState;
                        }                        
                        this.getCheckData();
                    },
                    //选择单个
                    checkOne: function(item) {
                        this.searchLists.every(function(item) {
                            return item.lineCheck == true;
                        }) ? this.checkAllState = true : this.checkAllState = false;                        
                        this.getCheckData();                        
                    },
                    //获取选中的数据
                    getCheckData: function() {
                        this.checkedList = this.searchLists.filter(function(item) {
                            return item.lineCheck == true;
                        })
                        
                        //选中的值显示到输入框中
                        this.selectCon='';
                        for(var i=0;i<this.checkedList.length;i++){
                            this.selectCon+=this.checkedList[i].lineName+',';
                        }                
                    },
                    //切换下拉列表
                    toggleList:function(){
                        this.isShow=!this.isShow;                        
                    },
                    //显示下拉列表
                    showList:function(){
                        this.isShow=true;                        
                    },
                    //文本框获得焦点时文字被选中
                    inputFocus:function(e){
                        e.currentTarget.select();
                    }                    
                },
                computed: {
                    //输入框筛选列表
                    searchLists: function() {
                        var _search = this.searchLine;
                        if (_search) {
                            return this.lineList.filter(function(item) {
                                return Object.keys(item).some(function(key) {
                                    return String(item.lineName).toLowerCase().indexOf(_search) > -1
                                })
                            })
                        }
                        return this.lineList;
                    }
                },                
                mounted:function(){
                    var _this=this;
                    //点击页面空白处隐藏下拉列表
                    document.addEventListener('click',function(){                        
                        _this.isShow=false;
                    });
                }
            });
        </script>
    </body>
</html>

 

css:

.m-select-wrap{width: 300px;margin: 20px auto 0;}
.m-select-wrap .title{width: 300px;position: relative;}
.m-select-wrap input[type="text"]{width: 300px;height: 40px;padding: 0 5px;}
.m-select-wrap .select-con{position: absolute;left: 105%;white-space: nowrap;line-height: 40px;}
.m-select-wrap .show-list{position: absolute; width: 30px;height: 40px;line-height: 38px;border: 1px solid #aaa;right: 0;text-align: center;cursor: pointer;}
.m-select-wrap ul{border: 1px solid #ccc;padding:0 30px 10px 10px;}
.m-select-wrap li{margin-top: 10px;}
posted @ 2020-01-03 15:35  后知后觉0107  阅读(4265)  评论(0编辑  收藏  举报