vue实现自定义el-table穿梭框功能
作者:Lemon今天学习了吗
这篇文章主要介绍了vue实现自定义el-table穿梭框功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
一、需求描述
前段时间接到一个需求是点击做一个类似穿梭框的表格点击选中功能,弹框的左边是全部数据展示,点击表格行数据可以选中自动增加到右边的已选框,并且可以手动删除、重置选中数据。
点击确定后到展示到主页面,被选中的数据打开弹框不能再次选择。
二、界面展示
功能如下图所示:
主页面没有选中的数据时,展示如下:
弹框页面,展示如下:
选中后主页面的数据显示如下:
再次点击添加学生成绩按钮,之前选中数据不可再点击,如下图:
三、代码实现
1.首页面表格主键是orderId ,主页面代码:
<div class="content-box"> <div class="table-title flex-between"> <span>学生成绩信息</span> <div style="text-align:end"> <el-button plain type="primary" @click="delSomeMedic()">批量删除</el-button> <el-button type="primary" @click="addMedic()">添加学生成绩</el-button> </div> </div> <div class="single-table"> <el-table ref="table" size="mini" height="100%" :data="tableData.adrDrugInfos" :header-cell-style="{background: '#fff',height:'40px'}" border @selection-change="handleSelectionChange"> <el-table-column type="selection" width="40"> </el-table-column> <el-table-column prop="dose" label="姓名" show-overflow-tooltip></el-table-column> <el-table-column prop="suspectedConcomitant" label="是否住校" show-overflow-tooltip width="100"> <template #default="scope"> <span v-if="scope.row.suspectedConcomitant == '1'">住校生</span> <span v-if="scope.row.suspectedConcomitant == '2'">非住校生</span> </template> </el-table-column> <el-table-column prop="doseUnit" label="数学" show-overflow-tooltip></el-table-column> <el-table-column prop="frequency" label="语文" show-overflow-tooltip></el-table-column> <el-table-column prop="routeName" label="英语" show-overflow-tooltip></el-table-column> <el-table-column prop="reasonForUse" label="备注" show-overflow-tooltip></el-table-column> <el-table-column label="操作" header-align="center" width="200" align="center" fixed="right"> <template slot-scope="scope"> <el-button size="small" style="color: #409eff; padding: 0" type="text" @click="editMedic(false,scope.row)">成绩详情</el-button> <el-button size="small" style="color: #409eff; padding: 0" type="text" @click="editMedic(true,scope.row)">编辑</el-button> <el-button size="small" style="color: #409eff; padding: 0" type="text" @click="delMedic(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> </div> //----------------------------------------------------------------------------- // 新增学生成绩信息 addMedic() { if (this.tableData.healthEventId == '') { return this.$message.warning('请先选择学生') } else { this.$refs.addMedicDialog.open( this.tableData.adrDrugInfos, this.tableData.healthEventId, this.tableData.visitType ) } }, // 删除学生成绩信息 delMedic(row) { this.$Confirm({ type: 'delete' }) .then((e) => { this.tableData.adrDrugInfos.map((item, index) => { if (item.orderId == row.orderId) { this.tableData.adrDrugInfos.splice(index, 1) this.$message.success('删除成功!') } }) }) .catch((err) => { console.log(err) }) }, //选中学生成绩信息数据 handleSelectionChange(val) { this.selectedMedicData = val }, // 批量学生成绩信息 delSomeMedic() { if (this.selectedMedicData.length <= 0) { return this.$message.warning('请先选择学生成绩信息') } this.$Confirm({ type: 'delete' }) .then((e) => { this.selectedMedicData.forEach((val) => { this.tableData.adrDrugInfos.forEach((v, i) => { if (val.orderId == v.orderId) { this.tableData.adrDrugInfos.splice(i, 1) this.$message.success('删除成功!') } }) }) }) .catch((err) => { console.log(err) }) }, // 选择学生成绩信息回显 getMedicalData(data) { data.forEach((item) => { this.tableData.adrDrugInfos.push({ orderId: item.orderId||'', suspectedConcomitant: item.suspectedConcomitant||'', dose: item.onceDosage||'', doseUnit: item.dosageunitName||'', frequency: item.freqDesc||'', routeName: item.defaultUsageCode||'', formName: item.drugForm||'', reasonForUse: item.reasonForUse||'', }) }) },
2.弹框页面数据主键是orderId,弹框页面代码:
<template> <el-dialog title="添加学生成绩" :visible.sync="dialogVisible" :close-on-click-modal="false" @close="close" append-to-body top="10vh !important" width="90%" > <div class="box-wrapper"> <div class="single-table-container left-table"> <div class="search-form-wrapper"> <div class="title">学生成绩列表</div> <div class="seach_list"> <el-input prefix-icon="el-icon-search" placeholder="学生姓名" v-model="searchForm.onceDosage" size="mini" clearable ></el-input> <el-date-picker v-model="dateTime" type="daterange" value-format="yyyy-MM-dd" format="yyyy-MM-dd" range-separator="—" @change="changeDateTime" start-placeholder="在校开始时间" end-placeholder="在校结束时间" > </el-date-picker> <el-button type="primary" size="mini" @click="searchTable" >查询</el-button > </div> </div> <div class="single-table"> <el-table ref="leftTable" v-loading="tableLoading" size="mini" height="370px" :data="tableData" stripe row-key="orderId" tooltip-effect="dark" :header-cell-style="{ background: '#f5f7fa', fontWeight: 'bold', color: '#303133' }" border @selection-change="handleSelectionChange" @row-click="handleClickTableRow" > <el-table-column type="selection" width="40" :reserve-selection="true" :selectable="handleSelected" ></el-table-column> <el-table-column type="index" header-align="center" align="center" label="序号" width="50" ></el-table-column> <el-table-column prop="onceDosage" label="姓名" show-overflow-tooltip width="120" :formatter="formartTableField" ></el-table-column> <el-table-column prop="startDateTime" label="在校开始时间" show-overflow-tooltip width="100" :formatter="formartTableField" ></el-table-column> <el-table-column prop="stopDateTime" label="在校结束时间" show-overflow-tooltip width="100" :formatter="formartTableField" ></el-table-column> <el-table-column prop="dosageunitName" label="数学" show-overflow-tooltip :formatter="formartTableField" ></el-table-column> <el-table-column prop="freqDesc" label="语文" show-overflow-tooltip :formatter="formartTableField" ></el-table-column> <el-table-column prop="defaultUsageCode" label="英语" show-overflow-tooltip :formatter="formartTableField" ></el-table-column> </el-table> </div> <div class="table-pagination"> <el-pagination class="pagination" @current-change="handleCurrentChange" :current-page="pages.pageIndex" :page-size="pages.pageSize" layout="total,prev, pager, next" :total="pages.total" ></el-pagination> </div> </div> <div class="single-table-container right-table"> <div class="search-form-wrapper"> <div class="title">已选学生</div> </div> <div class="single-table"> <el-form :model="selectedForm" ref="selectedForm" :rules="selectedForm.rules" > <el-table ref="rightTable" size="mini" height="410px" :data="selectedForm.selectedData" stripe tooltip-effect="dark" :header-cell-style="{ background: '#f5f7fa', fontWeight: 'bold', color: '#303133' }" border > <el-table-column type="index" header-align="center" align="center" label="序号" width="50" ></el-table-column> <el-table-column prop="onceDosage" label="姓名" width="120" show-overflow-tooltip ></el-table-column> <el-table-column label="住校生/非住校生" show-overflow-tooltip width="188" > <template #default="scope"> <el-form-item :prop=" 'selectedData.' + scope.$index + '.suspectedConcomitant' " > <el-radio-group v-model="scope.row.suspectedConcomitant" size="mini" > <el-radio label="1">住校生</el-radio> <el-radio label="2">非住校生</el-radio> </el-radio-group> </el-form-item> </template> </el-table-column> <el-table-column label="选择原因" show-overflow-tooltip> <template #default="scope"> <el-form-item :prop="'selectedData.' + scope.$index + '.reasonForUse'" :rules="selectedForm.rules.reasonForUse" > <el-input placeholder="请输入" v-model="scope.row.reasonForUse" clearable ></el-input> </el-form-item> </template> </el-table-column> <el-table-column label="操作" header-align="center" align="center" width="80" > <template slot-scope="scope"> <el-button size="small" style="color: #409eff; padding: 0" type="text" @click="del(scope.row)" >删除</el-button > </template> </el-table-column> </el-table> </el-form> </div> </div> </div> <span slot="footer" class="dialog-footer"> <el-button @click="reset">重置</el-button> <el-button :loading="btn_loading" type="primary" @click="submit" >确认</el-button > </span> </el-dialog> </template> <script> import { getAdviceRec } from '@/api/adr/report-manage-service' export default { components: {}, data() { return { dialogVisible: false, tableLoading: false, btn_loading: false, healthEventId: '', visitType: '', searchForm: { onceDosage: '', startDateTime: '', stopDateTime: '' }, dateTime: [], selectedForm: { selectedData: [], rules: { reasonForUse: [ { required: true, message: '请输入选中学生的原因', trigger: 'blur' } ] } }, pages: { pageIndex: 1, pageSize: 10, total: 0 }, tableData: [ { orderId: 1, onceDosage: '张三', startDateTime: '2020-01-01', stopDateTime: '2023-01-01', dosageunitName: '98', freqDesc: '95', defaultUsageCode: '99' }, { orderId: 2, onceDosage: '李四', startDateTime: '2020-01-01', stopDateTime: '2023-05-01', dosageunitName: '100', freqDesc: '92', defaultUsageCode: '95' }, { orderId: 3, onceDosage: '王五', startDateTime: '2021-01-01', stopDateTime: '2023-02-01', dosageunitName: '98', freqDesc: '95', defaultUsageCode: '100' }, { orderId: 4, onceDosage: '赵六', startDateTime: '2021-06-01', stopDateTime: '2024-01-01', dosageunitName: '98', freqDesc: '100', defaultUsageCode: '90' } ], pSelectedData: [] // 父级数据 } }, methods: { open(data, healthEventId, visitType) { this.healthEventId = healthEventId || '' this.visitType = visitType || '' this.dialogVisible = true if (!!data && data.length > 0) { this.pSelectedData = data } else { this.pSelectedData = [] } this.initTable() }, initTable() { this.tableLoading = true let params = { current: this.pages.pageIndex, size: this.pages.pageSize, visitType: this.visitType, healthEventId: this.healthEventId, startDateTime: this.searchForm.startDateTime, stopDateTime: this.searchForm.stopDateTime, onceDosage: this.searchForm.onceDosage } params = useKyyDelNullProperty(params) getAdviceRec(params) .then((res) => { if (res.code == 200) { this.tableLoading = false this.tableData = res.result.records this.pages.total = res.result.total // 默认在校 this.tableData.forEach((item) => { this.$set(item, 'suspectedConcomitant', '1') }) // 固定对齐表格 this.$nextTick(() => { this.$refs.leftTable.doLayout() }) } else { this.$message.error(`错误:${res.message}`) } }) .catch((err) => {}) setTimeout(() => { this.tableLoading = false }, 5000) }, handleSelectionChange(val) { this.selectedForm.selectedData = val }, close() { this.dialogVisible = false this.searchForm.onceDosage = '' this.searchForm.startDateTime = '' this.searchForm.stopDateTime = '' this.reset() }, reset() { this.btn_loading = false this.$refs.leftTable.clearSelection() }, // 删除 del(row) { // 取消选中 this.selectedForm.selectedData.map((item, index) => { if (item.orderId == row.orderId) { this.selectedForm.selectedData.splice(index, 1) this.$refs.leftTable.toggleRowSelection(row, false) } }) }, // 点击行勾选数据 handleClickTableRow(row, event, column) { if (!this.handleSelected(row)) return false if (this.selectedForm.selectedData.length > 0) { // 如果结果数组不为空,判断所选的这条是否在结果数组里 if ( JSON.stringify(this.selectedForm.selectedData).indexOf( JSON.stringify(row.orderId) ) == -1 ) { this.selectedForm.selectedData.push(row) this.$refs.leftTable.toggleRowSelection(row, true) } else { // 取消选中 this.selectedForm.selectedData.map((item, index) => { if (item.orderId == row.orderId) { this.selectedForm.selectedData.splice(index, 1) this.$refs.leftTable.toggleRowSelection(row, false) } }) } } else { this.selectedForm.selectedData.push(row) this.$refs.leftTable.toggleRowSelection(row, true) } }, // 已选数据不可再选,通过比较orderId 是否一致 handleSelected(row, index) { if (this.pSelectedData?.length > 0) { if ( this.pSelectedData.some((el) => { return el.orderId == row.orderId }) ) { return false } else { return true } } else { return true } }, submit() { this.btn_loading = true if (this.selectedForm.selectedData.length > 0) { this.$refs.selectedForm.validate(async (valid) => { if (valid) { this.$emit('getMedicalData', this.selectedForm.selectedData) this.close() this.$message.success('操作成功') } else { return this.$message.warning('请输入选择原因') } }) } else { this.$message.warning('请选择要添加的学生成绩信息') } this.btn_loading = false }, // 分页栏 handleCurrentChange(val) { this.pages.pageIndex = val this.initTable() }, formartTableField(row, column, cellValue, index) { if (cellValue) { return cellValue } return '-' }, changeDateTime(data) { if (data) { this.searchForm.startDateTime = data[0] this.searchForm.stopDateTime = data[1] } else { this.searchForm.startDateTime = '' this.searchForm.stopDateTime = '' } }, // 查询 searchTable() { if (!!this.dateTime && this.dateTime.length > 0) { this.searchForm.startDateTime = this.dateTime[0] this.searchForm.stopDateTime = this.dateTime[1] } this.pages.pageIndex = 1 this.initTable() } } } </script> <style lang="scss" scoped> .box-wrapper { font-size: 14px; display: flex; justify-content: space-between; .left-table { width: 51%; padding: 0; } .right-table { width: 48%; padding: 0; .el-input { width: 100%; } .el-form-item { margin: 0; } .el-radio-group { :deep(.el-radio) { margin-right: 10px; .el-radio__label { font-size: 12px; padding-left: 10px; } } } } } //单页表格 .single-table-container { width: 100%; height: 100%; padding: 10px; overflow: auto; .search-form-wrapper { height: 40px; display: flex; align-items: center; border: 1px solid #e6eaef; border-bottom: none; padding: 0 10px; .title { font-size: 14px; font-weight: 700; color: #303133; } } .single-table { height: calc(100% - 80px); .inner_table { padding: 10px; // background: rgba(25, 137, 254, 0.1); margin-top: -4px; margin-bottom: -4px; } } .table-pagination { text-align: right; height: 40px; background: #fff; border: 1px solid #e6eaef; border-top: unset; .el-pagination { padding: 6px 10px; } } } </style>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。