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;}