基于vue+element ui实现下拉表格选择组件
一:前言
二:正文
1:示例展示
单选
多选
index.vue
<template> <el-select ref="select" v-model="defaultValue" :title="isNeedTitle ? getTitle() : null" :clearable="false" :multiple="multiple" :filterable="false" :placeholder="placeholder" :disabled="disabled" :value-key="defaultProps.value" :filter-method="filterMethod" @remove-tag="removeTag" @visible-change="visibleChange" @clear="clear" > <template #empty> <div class="sc-table-select__table" :style="{ width: tableWidth + 'px' }" v-loading="loading" > <div class="sc-table-select__header"> <slot name="header" :form="formData" :submit="formSubmit"></slot> </div> <el-table ref="table" style="font-size: 16px" :data="tableData" :height="245" :highlight-current-row="!multiple" @row-click="rowClick" @select="select" @select-all="selectAll" reserve-selection > <el-table-column v-if="multiple" type="selection" width="45" ></el-table-column> <el-table-column v-else type="index" width="45"> <template #default="scope" ><span>{{ scope.$index + (currentPage - 1) * pageSize + 1 }}</span></template > </el-table-column> <slot></slot> </el-table> <div class="sc-table-select__page"> <el-pagination small background layout="prev, pager, next" :total="total" :page-size="pageSize" :current-page.sync="currentPage" @current-change="currentChange" ></el-pagination> </div> </div> </template> </el-select> </template> <script> import config from './tableSelect' export default { props: { value: { type: [String, Number, Array, Object], default: '' }, // Not Request,all Table Data tabularData: { type: Array, default: () => [] }, // 是否是需要请求 isNeedRequest: { type: Boolean, default: false }, // 数据value是否以逗号隔开 isDataJoin: { type: Boolean, default: true }, // 请求url requestUrl: { type: Function, default: Function }, params: { type: Object, default: () => {} }, placeholder: { type: String, default: '请选择' }, multiple: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, tableWidth: { type: Number, default: 400 }, mode: { type: String, default: 'popover' }, // 合并默认配置 props: { type: Object, default: () => {} }, // 合并默认配置 isNeedTitle: { type: Boolean, default: false }, // 是否需要数据过滤 isNeedDataFilter: { type: Boolean, default: false }, filterParam: { type: Object, default: () => {} } }, data() { return { loading: false, keyword: null, defaultValue: [], tableData: [], pageSize: config.pageSize, total: 0, currentPage: 1, defaultProps: { label: config.props.label, value: config.props.value, page: config.request.page, pageSize: config.request.pageSize, keyword: config.request.keyword }, formData: {}, // Not Request,Need Table Data tabularMap: {} } }, watch: { value: { handler() { this.$nextTick(() => { if (!this.isDataJoin) { if (this.multiple) { this.defaultValue = this.value || [] } else { this.defaultValue = this.value } } else { // 多选 if (this.multiple) { this.defaultValue = Array.isArray(this.value) ? this.value : this.value ? this.value.split(',') : [] this.defaultValue = (this.defaultValue || []).map(item => { return { [this.defaultProps.value]: item } }) } else { this.defaultValue = this.value ? { [this.defaultProps.value]: this.value } : '' } } this.findLabel() }) }, deep: true, immediate: true }, tabularData: { handler(val) { if (this.isNeedRequest) return this.$nextTick(() => { val.forEach(item => { this.tabularMap[item[this.defaultProps.value]] = item[this.defaultProps.label] }) this.findLabel() }) }, deep: true, immediate: true } }, created() { // bug,在这不能使用nextTick this.defaultProps = Object.assign(this.defaultProps, this.props) }, methods: { // 表格显示隐藏回调 visibleChange(visible) { if (visible) { this.currentPage = 1 this.keyword = null this.formData = {} this.getData() } else { this.findLabel() } }, // 获取表格数据 async getData() { if (this.isNeedRequest) { this.initTable() } else { this.initTabularData() } }, initTabularData() { // this.tableData = deepClone(this.tabularData) this.total = this.tabularData.length this.tableData = this.tabularData.slice((this.currentPage - 1) * this.pageSize, this.currentPage * this.pageSize) if (Object.keys(this.formData).length > 0) { const input = this.formData[this.defaultProps.label] if (input) { const arr = this.tabularData.filter((item) => { return String(item[this.defaultProps.label]).toLowerCase().match(input) }) this.total = arr.length this.tableData = arr.slice((this.currentPage - 1) * this.pageSize, this.currentPage * this.pageSize) } } // 表格默认赋值 this.$nextTick(() => { if (this.multiple) { this.defaultValue.forEach(row => { const arr = this.tableData.filter(item => item[this.defaultProps.value] === row[this.defaultProps.value]) if (arr.length > 0) { this.$refs.table.toggleRowSelection(arr[0], true) } }) } else { const arr = this.tableData.filter(item => item[this.defaultProps.value] === this.defaultValue[this.defaultProps.value]) this.$refs.table.setCurrentRow(arr[0]) } this.$refs.table.$el.querySelector('.el-table__body-wrapper').scrollTop = 0 }) }, async initTable() { this.loading = true var reqData = { [this.defaultProps.page]: this.currentPage, [this.defaultProps.pageSize]: this.pageSize, [this.defaultProps.keyword]: this.keyword } Object.assign(reqData, this.params, this.formData) var res = await this.requestUrl(reqData) var parseData = config.parseData(res) this.tableData = parseData.list this.total = parseData.total this.loading = false // 表格默认赋值 this.$nextTick(() => { if (this.multiple) { this.defaultValue.forEach((row) => { const arr = this.tableData.filter(item => item[this.defaultProps.value] === row[this.defaultProps.value]) if (arr.length > 0) { this.$refs.table.toggleRowSelection(arr[0], true) } }) } else { const arr = this.tableData.filter(item => item[this.defaultProps.value] === this.defaultValue[this.defaultProps.value]) this.$refs.table.setCurrentRow(arr[0]) } this.$refs.table.$el.querySelector('.el-table__body-wrapper').scrollTop = 0 }) }, // 插糟表单提交 formSubmit() { this.currentPage = 1 this.keyword = null this.getData() }, // 分页刷新表格 currentChange(val) { this.currentPage = val this.getData() }, // 赋值 findLabel() { this.$nextTick(() => { if (this.multiple) { this.$refs.select.selected.forEach((item) => { if (this.isNeedRequest) { item.currentLabel = item.value[this.defaultProps.label] } else { item.currentLabel = this.tabularMap[item.value[this.defaultProps.value]] } }) } else { if (this.isNeedRequest) { this.$refs.select.selectedLabel = this.defaultValue[this.defaultProps.label] || '' } else { this.$refs.select.selectedLabel = this.tabularMap[this.defaultValue[this.defaultProps.value]] || '' } } }) }, // 表格勾选事件 select(rows, row) { var isSelect = rows.length && rows.indexOf(row) !== -1 // tip:row属于rows里的数据,同一地址,所以可判断 if (isSelect) { // console.log(row, 'row') this.defaultValue.push(row) if (this.isNeedDataFilter) { var flag = false if (+row[this.filterParam.key] == this.filterParam.value) { flag = true } } this.dataFilter(flag) } else { this.defaultValue.splice(this.defaultValue.findIndex(item => item[this.defaultProps.value] === row[this.defaultProps.value]), 1) } if (this.isDataJoin) { this.defaultValue = this.defaultValue.map(item => item[this.defaultProps.value]).join(',') } this.findLabel() this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) }, // 表格全选事件 selectAll(rows) { var isAllSelect = rows.length > 0 if (isAllSelect) { var flag = false rows.forEach(row => { var isHas = this.defaultValue.find(item => item[this.defaultProps.value] === row[this.defaultProps.value]) if (!isHas) { this.defaultValue.push(row) if (this.isNeedDataFilter) { if (+row[this.filterParam.key] == this.filterParam.value) { flag = true } } } }) this.dataFilter(flag) } else { this.tableData.forEach(row => { const index = this.defaultValue.findIndex(item => item[this.defaultProps.value] === row[this.defaultProps.value]) if (index !== -1) { this.defaultValue.splice(index, 1) } }) } if (this.isDataJoin) { this.defaultValue = this.defaultValue.map(item => item[this.defaultProps.value]).join(',') } this.findLabel() this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) }, async rowClick(row) { if (this.multiple) { // 处理多选点击行 this.$refs.table.toggleRowSelection(row) const isSelect = this.defaultValue.filter(item => item.bizid === row.bizid).length !== 0 let oldDefaultValue = [...this.defaultValue] || [] if (isSelect) oldDefaultValue = this.defaultValue.filter(item => item.bizid !== row.bizid) if (!isSelect) oldDefaultValue.push(row) this.select(oldDefaultValue || [], row) } else { this.defaultValue = '' this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) await this.$nextTick() this.defaultValue = row if (this.isDataJoin) { this.defaultValue = row[this.defaultProps.value] } this.$refs.select.blur() this.findLabel() this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) } }, // tags删除后回调 removeTag(tag) { var row = this.findRowByKey(tag[this.defaultProps.value]) this.$refs.table.toggleRowSelection(row, false) if (this.isDataJoin) { this.defaultValue = this.defaultValue.map(item => item[this.defaultProps.value]).join(',') } this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) }, // 清空后的回调 clear() { this.$emit('input', this.defaultValue) this.$emit('change', this.defaultValue) }, // 关键值查询表格数据行 findRowByKey(value) { return this.tableData.find(item => item[this.defaultProps.value] === value) }, filterMethod(keyword) { if (!keyword) { this.keyword = null return false } this.keyword = keyword this.getData() }, // 触发select隐藏 blur() { this.$refs.select.blur() }, // 触发select显示 focus() { this.$refs.select.focus() }, async getTitle() { try { await this.$nextTick() const title = [] if (!this.isNeedRequest) { const map = {} for (const item of this.tabularData) { map[item[this.defaultProps.value]] = item[this.defaultProps.label] } if (this.multiple) { for (const v of this.defaultValue || []) { title.push(map[v[[this.defaultProps.value]]]) } } else { return map[this.defaultValue[this.defaultProps.value]] || '' } } return title.length > 0 ? title.join(',') : '' } catch (error) { return '' } }, dataFilter(flag) { if (!this.isNeedRequest && this.multiple && this.isNeedDataFilter) { this.defaultValue = this.defaultValue.filter(v => { const tepArr = this.tabularData.filter(i => { if (flag) { return i[this.filterParam.key] != this.filterParam.value } else { return i[this.filterParam.key] == this.filterParam.value } }) const tepVal = tepArr.find(t => t[this.defaultProps.value] === v[this.defaultProps.value]) if (tepVal) { this.$refs.table.toggleRowSelection(tepVal, false) return false } return true }) } } } } </script> <style scoped> .sc-table-select__table { padding: 12px; } .sc-table-select__page { padding-top: 12px; } </style>
tableSelect.js
// 表格选择器配置 export default { pageSize: 20, // 表格每一页条数 parseData: function(res) { return { data: res.data, list: res.data.data.list, // 分析行数据字段结构 total: res.data.data.total, // 分析总数字段结构 msg: res.data.message, // 分析描述字段结构 code: res.data.code // 分析状态字段结构 } }, request: { page: 'page', // 规定当前分页字段 pageSize: 'pageSize', // 规定一页条数字段 keyword: 'keyword' // 规定搜索字段 }, props: { label: 'label', // 映射label显示字段 value: 'value' // 映射value值字段 } }
使用
<template> <!-- 单选用法 --> <YyTableSelect v-model="xxx" :props="props" :tabularData="table" :table-width="600" @change="change()"> <el-table-column prop="parameterName" label="参数名称"></el-table-column> <el-table-column prop="parameterScore" label="分值" width="180"></el-table-column> </YyTableSelect> <!-- 多选用法 --> <YyTableSelect v-model="value" :apiObj="apiObj" :table-width="700" multiple :props="props" @change="change" > <template #header="{ form, submit }"> <el-form :inline="true" :model="form"> <el-form-item> <el-select v-model="form.sex" placeholder="性别" clearable :teleported="false" > <el-option label="男" value="1"></el-option> <el-option label="女" value="2"></el-option> </el-select> </el-form-item> <el-form-item> <el-date-picker v-model="form.date" value-format="YYYY-MM-DD" type="date" placeholder="时间" :teleported="false" ></el-date-picker> </el-form-item> <el-form-item> <el-button type="primary" @click="submit">查询</el-button> </el-form-item> </el-form> </template> <el-table-column prop="id" label="ID" width="180"></el-table-column> </YyTableSelect> </template> <script> import YyTableSelect from '@/views/components/YyTableSelect' export default { components: { YyTableSelect }, data() { return { params: { name: '' }, value: [ { id: '1', user: 'xx' }, { id: '2', user: 'xx' } ], props: { label: 'label', value: 'value', keyword: 'keyword' } } }, computed: {}, mounted() {}, methods: { // 值变化 change(val) { console.log(val) } } } </script> <style scoped></style>
根据https://lolicode.gitee.io/scui-doc/demo/#/dashboard里的组件修改
为人:谦逊、激情、博学、审问、慎思、明辨、 笃行
学问:纸上得来终觉浅,绝知此事要躬行
为事:工欲善其事,必先利其器。
态度:道阻且长,行则将至;行而不辍,未来可期
.....................................................................
------- 桃之夭夭,灼灼其华。之子于归,宜其室家。 ---------------
------- 桃之夭夭,有蕡其实。之子于归,宜其家室。 ---------------
------- 桃之夭夭,其叶蓁蓁。之子于归,宜其家人。 ---------------
=====================================================================
* 博客文章部分截图及内容来自于学习的书本及相应培训课程以及网络其他博客,仅做学习讨论之用,不做商业用途。
* 如有侵权,马上联系我,我立马删除对应链接。 * @author Alan -liu * @Email no008@foxmail.com
转载请标注出处! ✧*꧁一品堂.技术学习笔记꧂*✧. ---> https://www.cnblogs.com/ios9/
学问:纸上得来终觉浅,绝知此事要躬行
为事:工欲善其事,必先利其器。
态度:道阻且长,行则将至;行而不辍,未来可期
.....................................................................
------- 桃之夭夭,灼灼其华。之子于归,宜其室家。 ---------------
------- 桃之夭夭,有蕡其实。之子于归,宜其家室。 ---------------
------- 桃之夭夭,其叶蓁蓁。之子于归,宜其家人。 ---------------
=====================================================================
* 博客文章部分截图及内容来自于学习的书本及相应培训课程以及网络其他博客,仅做学习讨论之用,不做商业用途。
* 如有侵权,马上联系我,我立马删除对应链接。 * @author Alan -liu * @Email no008@foxmail.com
转载请标注出处! ✧*꧁一品堂.技术学习笔记꧂*✧. ---> https://www.cnblogs.com/ios9/