1. 程式人生 > >vue實現下拉框全選和輸入匹配

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:

@charset "utf-8";

*{margin: 0;padding: 0;list-style: none;box-sizing: border-box;font-size: 100%;}
.m-map-screen{width: 100%;margin: 50px auto 100px;height: 40px;}
.m-map-screen .screen-box{float: left;position: relative;  margin-left: 30px;background: #fff;height: 40px;}
.m-map-screen .screen-box select{height: 40px;}
.m-map-screen .screen-box h2.title{font-weight: normal;padding:0 10px;border:1px solid #ccc;height: 40px;}
.m-map-screen .screen-data{position: absolute;display: none;top: 40px;left: 0;}
.map-con{width: 100px;height: 100px;border: 1px solid #ccc;clear: both;margin: 20px 0 0 20px;display: none;}
.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;}