vue實現下拉框全選和輸入匹配
阿新 • • 發佈:2020-01-03
實際專案中的一個需求:
點選文字框,彈出帶有複選框的選項,然後獲取選中項的資料,傳給後面的一個功能。在文字框輸入內容,也會動態的匹配下拉列表,並且列表帶有全選功能。
樸素的效果圖:
我選擇了用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;}