前提:必须先安装了element-ui
自定义开发带分页以及搜索框的select
用法
select.vue文件
<template> <div v-clickoutside="()=>visible=false" class="com-select"> <div ref="reference" class="com-select-input" @click="clickSelectInput"> <div class="one"></div> <!-- tags展示 --> <div class="two"> <template v-if="isCheckAll"> <el-tag size="small" closable hit type="info" disable-transitions @close="cancelCheckAll()"> <span class="el-select__tags-text">全选</span> </el-tag> </template> <template v-else> <el-tag v-for="item in selectedArr" :key="item.value" size="small" closable hit type="info" disable-transitions @close="deleteTag(item)"> <span class="el-select__tags-text">{{ item.label }}</span> </el-tag> </template> </div> <div class="three" @mouseenter.stop="inputHovering = true" @mouseleave.stop="inputHovering = false" > <i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click.stop="cancelCheckAll"></i> <i v-else :class="`el-icon-arrow-${visible ? ‘up‘ : ‘down‘} el-select__caret el-input__icon`"></i> </div> </div> <transition name="el-zoom-in-top"> <!-- 下拉框 --> <the-select-menu v-show="visible" ref="popper" append-to-body> <!-- 搜索框 --> <el-input v-model="queryVal" placeholder="请输入" size="small" clearable @input="handleSearch" @keyup.enter.native="handleSearch"> <el-button slot="append" icon="el-icon-search" @click="handleSearch"></el-button> </el-input> <!-- select选项 --> <div class="com-select-body"> <div v-for="(item, i) in list" v-show="isShowFilterArr ? item._isShow : item.isShow" :key="item.value" :title="item.label" :style="formatColumn()" :class="[‘com-option‘, {‘selected‘: item.selected,}]" @click="selectOptionClick(item, i)" > {{ item.label }} </div> <div v-if="list.length === 0" class="com-select-nodata">暂无数据</div> <template v-if="nextPageStaus"> <i :style="formatColumn()" v-for="v in 3" :key="‘AA‘ + v"></i> </template> </div> <!-- 分页 --> <div class="com-footer-page"> <el-button size="small" :disabled="prePageStaus" @click="prePage">上一页</el-button> <el-button type="primary" size="small" @click="checkAll">全选</el-button> <el-button size="small" :disabled="nextPageStaus" @click="nextPage">下一页</el-button> </div> </the-select-menu> </transition> </div> </template> <script> import TheSelectMenu from ‘./select-dropdown.vue‘; import Clickoutside from ‘element-ui/src/utils/clickoutside‘; export default { name: ‘SelectPro‘, components: { TheSelectMenu }, directives: { Clickoutside }, props: { value: { type: Array, default: () => [], required: true }, options: { type: Array, default: () => [] }, column: { type: Number, default: 3 } }, data() { return { optionArr: this.initOptions(), inputHovering: false, selectedArr: [], filterArr: [], queryVal: ‘‘, visible: false, pageSize: this.column * 4, currentPage: 1, filterCurrentPage: 1 }; }, computed: { list() { return this.isShowFilterArr ? this.filterArr : this.optionArr; }, isCheckAll() { return this.selectedArr.length === this.optionArr.length; }, isShowFilterArr() { return this.filterArr.length > 0 || this.queryVal !== ‘‘; }, showClose() { return this.selectedArr.length > 0 && this.inputHovering; }, prePageStaus() { if (this.isShowFilterArr ? this.filterCurrentPage === 1 : this.currentPage === 1) { return true; } return false; }, nextPageStaus() { const len = Math.ceil(this.list.length / this.pageSize); if (len === 0) return true; if (this.isShowFilterArr ? this.filterCurrentPage === len : this.currentPage === len) { return true; } return false; } }, watch: { selectedArr(val) { const arr = val.map(item => { return item.value; }); this.$emit(‘input‘, arr); }, // value(val, oldVal) { // console.log(‘v-model===>‘,val, oldVal); // } }, mounted() { // 默认选中 this.optionArr.forEach(item => { if (this.value.includes(item.value)) { this.selectedArr.push(item); } }); }, methods: { initOptions() { return this.options.map((item, i) => { return { isShow: i < this.column * 4, _isShow: false, selected: this.value.includes(item.value), ...item }; }); }, deleteTag(item) { // 删除当前tag this.selectedArr.some((v, i) => { if (v.value === item.value) { item.selected = false; this.selectedArr.splice(i, 1); return true; } }); }, handleSearch() { // 搜索过滤 if (this.queryVal === ‘‘) { // 输入框清空时 this.filterArr = []; return; } console.log(this.queryVal); // 搜索前清除之前搜索的 this.filterArr = []; // 重置搜索数组分页 this.filterCurrentPage = 1; let num = 0; this.optionArr.forEach(item => { if (item.label.indexOf(this.queryVal) !== -1) { // 如果like 输入值 item._isShow = num < this.pageSize; // 只展示一页的结果 this.filterArr.push(item); num++; } }); }, clickSelectInput() { // 点击输入框 this.visible = !this.visible; }, selectOptionClick(item, index) { // 单击check item.selected = !item.selected; // 如果已经选过 if (this.selectedArr.some(v => v.value === item.value)) { this.deleteTag(item); } else { this.selectedArr.push(item); } }, checkAll() { // 全选 this.selectedArr = []; this.optionArr.forEach(item => { item.selected = true; this.selectedArr.push(item); }); }, cancelCheckAll() { // 取消全选 this.optionArr.forEach(item => { item.selected = false; }); this.selectedArr = []; }, prePage() { // 上一页 if (this.isShowFilterArr) { // 搜索展示时 this.changeFilterPageShow(false); this.filterCurrentPage--; this.changeFilterPageShow(true); } else { this.changePageShow(false); this.currentPage--; this.changePageShow(true); } }, nextPage() { // 下一页 if (this.isShowFilterArr) { // 搜索展示时 this.changeFilterPageShow(false); this.filterCurrentPage++; this.changeFilterPageShow(true); } else { this.changePageShow(false); this.currentPage++ this.changePageShow(true); } }, changePageShow(isOrNo) { // 改变当前页状态 const num = (this.currentPage - 1) * this.pageSize; const num2 = num + this.pageSize; for (let index = num; index < num2; index++) { if (this.optionArr[index]) this.optionArr[index].isShow = isOrNo; } }, changeFilterPageShow(isOrNo) { // 改变搜索当前页状态 const num = (this.filterCurrentPage - 1) * this.pageSize; const num2 = num + this.pageSize; for (let index = num; index < num2; index++) { if (this.filterArr[index]) this.filterArr[index]._isShow = isOrNo; } }, formatColumn() { // 展示多少列 if (this.column === 1) { return { width: ‘100%‘ }; } else if (this.column === 2) { return { width: ‘49%‘ }; } else if (this.column === 3) { return { width: ‘32%‘ }; } else { return { width: ‘24%‘ }; } } } }; </script> <style lang="less" scoped> .com-select { box-sizing: border-box; border-radius: 4px; border: 1px solid #DCDFE6; cursor: pointer; background: #ffffff; .com-select-input { display: flex; align-items: center; .one { width: 10px; } .two { flex: 1; line-height: 29px; padding: 0 0 1px 0; /deep/ .el-tag { background-color: #f4f4f5; border-color: #e9e9eb; color: #909399; margin-right: 6px; } /deep/ .el-tag__close.el-icon-close { background-color: #C0C4CC; } } .three { width: 30px; } } } .el-select-dropdown { height: 280px; padding: 10px; border: 1px solid #E4E7ED; border-radius: 4px; box-shadow: 1px 2px 6px 0px #7d7d7d; box-sizing: border-box; cursor: default; .com-select-body { height: 178px; display: flex; flex-wrap: wrap; justify-content: space-between; align-content: flex-start; .com-option { // width: 32%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #606266; background-color: rgb(240, 248, 250); border: 1px solid #d7e8fa; height: 32px; line-height: 32px; box-sizing: border-box; position: relative; text-align: center; margin-bottom: 10px; cursor: pointer; } // 选中样式 .selected { border-color: #409EFF; &::after{ content: ‘‘; width: 15px; height: 14px; background: url("./check.png") no-repeat 0 0; position: absolute; right: 0; bottom: 0; } } .com-select-nodata { width: 100%; text-align: center; } } // 分页样式 .com-footer-page { display: flex; justify-content: space-between; } } </style>
select-down.vue文件
<template> <div class="el-select-dropdown el-popper" :style="{ width: width }"> <slot></slot> </div> </template> <script> export default { name: ‘MySelectDropdown‘, data() { return { width: ‘‘ }; }, mounted() { this.width = this.$parent.$el.clientWidth + ‘px‘; window.addEventListener(‘resize‘, this.resizeWindth); }, methods: { resizeWindth() { this.width = this.$parent.$el.clientWidth + ‘px‘; } } }; </script>