實際項目中的一個需求:
點擊文本框,彈出帶有復選框的選項,然后獲取選中項的數據,傳給后面的一個功能。在文本框輸入內容,也會動態的匹配下拉列表,並且列表帶有全選功能。
朴素的效果圖:
我選擇了用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;}