当我们对于主子表数据同时保存的时候,我们又不想做弹窗一条一条的新增子表数据的时候,并且子表数据并不是特别复杂,完全可用table来操作,这种情况下可选择可编辑列表来完成主子表的同时操作。
基于Tlement-Table编写,并借助于一些表单元素控件。实现表格数据的填写。以及表格操作,包括:新增行,删除行,插入行,上移,下移,置顶,置底等功能。废话不多说直接上代码。
包含对每一行数据的简单校验。
<template> <el-row> <el-card> <el-row class="text-right m-b"> <el-button type="primary" @click="handleAdd()"> 添加行 </el-button> <el-button type="danger" plain @click="batchRemove"> 删除行 </el-button> <el-button type="primary" @click="handleInsert"> 插入行 </el-button> <el-button type="primary" @click="handleMove(1)"> 上移 </el-button> <el-button type="primary" @click="handleMove(0)"> 下移 </el-button> <el-button type="primary" @click="handleTopOrBottom(1)"> 置顶 </el-button> <el-button type="primary" @click="handleTopOrBottom(0)"> 置底 </el-button> <el-button type="primary" @click="clearList"> 清空 </el-button> </el-row> <el-form ref="form2" :model="submitData" :rules="rules" label-width="150px"> <el-row :span="24"> <el-table ref="studentTable" :data="submitData.studentTableData" style="width: 100%" highlight-current-row stripe border :row-class-name="tableRowClassName" @current-change="currentChange" @selection-change="clickLogCheckboxHandler" > <el-table-column type="index" label="序号" width="80" /> <el-table-column prop="studentCode" label="学号" > <template slot-scope="scope"> <el-form-item :prop="'studentTableData.'+scope.$index+'.studentCode'" :rules="rules.studentTableDataRules.studentCode" label-width="0"> <el-input v-if="scope.row.showFormDom" v-model="scope.row.studentCode"/> <div v-else> {{ scope.row.studentCode }} </div> </el-form-item> </template> </el-table-column> <el-table-column prop="studentName" label="学生姓名" > <template slot-scope="scope"> <el-form-item :prop="'studentTableData.'+scope.$index+'.studentName'" :rules="rules.studentTableDataRules.studentName" label-width="0"> <el-input v-if="scope.row.showFormDom" v-model="scope.row.studentName"/> <div v-else> {{ scope.row.studentName }} </div> </el-form-item> </template> </el-table-column> <el-table-column prop="studentAge" label="学生年龄" > <template slot-scope="scope"> <el-form-item :prop="'studentTableData.'+scope.$index+'.studentAge'" :rules="rules.studentTableDataRules.studentAge" label-width="0"> <el-input v-if="scope.row.showFormDom" v-model="scope.row.studentAge"/> <div v-else> {{ scope.row.studentAge }} </div> </el-form-item> </template> </el-table-column> <el-table-column prop="studentSex" label="学生性别" > <template slot-scope="scope"> <el-form-item :prop="'studentTableData.'+scope.$index+'.studentSex'" :rules="rules.studentTableDataRules.studentSex" label-width="0"> <el-input v-if="scope.row.showFormDom" v-model="scope.row.studentSex"/> <div v-else> {{ scope.row.studentSex }} </div> </el-form-item> </template> </el-table-column> </el-table> </el-row> <el-row class="text-center m-t"> <el-button type="primary" @click="submitHandler"> 保存 </el-button> </el-row> </el-form> </el-card> </el-row> </template>
data() { return { // 选中的行 selected: null, rowIndex: 0, // 提交数据 submitData: { studentTableData: [] }, // 校验信息 rules: { studentTableDataRules: { studentName: [ { required: true, message: '请输入学生姓名', trigger: 'blur' } ], studentCode: [ { required: true, message: '请输入学号', trigger: 'blur' } ], studentAge: [ { required: true, message: '请输入学生年龄', trigger: 'blur' } ], studentSex: [ { required: true, message: '请输入学生性别', trigger: 'blur' } ] } }, // 多选情况下多选数据存储 selecteds: [] } }注:多选情况。
clickLogCheckboxHandler(selection) { this.selecteds = selection }注:由于row中获取不到索引值,无法操作数组中的数据,因此增加此方法为row增加索引值。
tableRowClassName({ row, rowIndex }) { row.row_index = rowIndex }注:此方法为列表底部新增一行,新增前会执行校验,并且新增行获得高亮;高亮方法为element-ui提供。
handleAdd() { const list = { studentCode: '', studentName: '', studentAge: '', studentSex: '', showFormDom: true } this.$refs['form2'].validate((valid) => { if (valid) { if (this.selected !== null) { const index = this.selected.row_index this.$set(this.submitData.studentTableData[index], 'showFormDom', false) } this.submitData.studentTableData.push(list) this.selected = list this.selected.row_index = this.submitData.studentTableData.length - 1 this.$refs.studentTable.setCurrentRow(this.submitData.studentTableData[this.selected.row_index]) } else { // 此处为验证失败代码 this.$message.warning('请先为当前行填值!') } }) }注:删除当前选中行
batchRemove() { this.$confirm('确认删除选中记录吗?', '提示', { type: 'warning' }) .then(() => { if (this.selected !== null) { this.submitData.studentTableData.splice(this.selected.row_index, 1) this.selected = null this.$message({ message: '删除成功', type: 'success' }) } else { this.$message({ message: '请选择要删除的行!', type: 'warning' }) } }) .catch(() => {}) }注:在选中数据上方插入一个空行
handleInsert() { if (this.selected !== null) { const list = { studentCode: '', studentName: '', studentAge: '', studentSex: '', showFormDom: true } if (this.submitData.studentTableData.length > 0) { this.$refs['form2'].validate((valid) => { if (valid) { const index = this.selected.row_index this.$set(this.submitData.studentTableData[index], 'showFormDom', false) this.submitData.studentTableData.splice(index, 0, list) this.selected = list this.selected.row_index = index this.$refs.studentTable.setCurrentRow(this.submitData.studentTableData[index]) } else { // 此处为验证失败代码 this.$message.warning('请先为当前行填值!') } }) } else { this.submitData.studentTableData.push(list) this.selected = list this.selected.row_index = 0 this.$refs.studentTable.setCurrentRow(this.submitData.studentTableData[0]) } } else { this.$message.warning('请选择插入位置!') } }注:根据传入标识判断上移,下移(1:上移;0:下移)
handleMove(dir) { if (this.selected !== null) { const moveComm = (curIndex, nextIndex) => { const arr = this.submitData.studentTableData arr[curIndex] = arr.splice(nextIndex, 1, arr[curIndex])[0] return arr } this.submitData.studentTableData.some((val, index) => { if (val.studentCode === this.selected.studentCode) { if (dir === 1 && index === 0) { this.$message.warning('已在顶部!') } else if (dir === 0 && index === this.submitData.studentTableData.length - 1) { this.$message.warning('已在底部!') } else { const nextIndex = dir === 1 ? index - 1 : index + 1 this.submitData.studentTableData = moveComm(index, nextIndex) } return true } return false }) } else { this.$message.warning('请选择操作的行!') } }注:根据传入标识判断置顶/置底(1:置顶;0:置底)
handleTopOrBottom(dir) { if (this.selected !== null) { const moveComm = (curIndex, nextIndex) => { const arr = this.submitData.studentTableData arr[curIndex] = arr.splice(nextIndex, 1, arr[curIndex])[0] return arr } this.submitData.studentTableData.some((val, index) => { if (val.studentCode === this.selected.studentCode) { if (dir === 1 && index === 0) { this.$message.warning('已在顶部!') } else if (dir === 0 && index === this.submitData.studentTableData.length - 1) { this.$message.warning('已在底部!') } else { const nextIndex = dir === 1 ? 0 : this.submitData.studentTableData.length - 1 this.submitData.studentTableData = moveComm(index, nextIndex) } return true } return false }) } else { this.$message.warning('请选择操作的行!') } }注:vue基于数据驱动,清空列表只需要清空列表数组数据即可。
clearList() { this.$confirm('确认执行清空操作吗?', '提示', { type: 'warning' }) .then(() => { this.submitData.studentTableData = [] this.selected = null this.$message({ message: '清空完成!', type: 'success' }) }) }注:由于这次编写的可编辑列表有这样一个特性,即:选中的行才可以编辑,未选中的行则是只读状态。因此在改变选中时应该增加一些操作。例如:对row.showFormDom的操作。还是直接看代码:
currentChange(newRow, oldRow) { if (this.selected !== null) { if (newRow.row_index !== this.selected.row_index) { this.$refs['form2'].validate((valid) => { if (valid) { const index = this.selected.row_index this.$set(this.submitData.studentTableData[newRow.row_index], 'showFormDom', true) this.$set(this.submitData.studentTableData[index], 'showFormDom', false) this.selected = newRow } else { // 此处为验证失败代码 this.$refs.studentTable.setCurrentRow(this.submitData.studentTableData[this.selected.row_index]) // this.$message.warning('请先为当前行填值!') } }) } } else { this.$set(this.submitData.studentTableData[newRow.row_index], 'showFormDom', true) this.selected = newRow } }注:这个应该无须赘述。
submitHandler() { this.$refs['form2'].validate((valid) => { if (valid) { this.$message({ showClose: true, message: '请完善列表中的数据!', type: 'warning' }) } else { this.$message({ showClose: true, message: '请完善列表中的数据!', type: 'warning' }) } }) } 可编辑列表常用的基本功能大致就想到了这么多,在就是本demo中表单元素均用input实现,对于其他需求,可以替换为其他表单元素控件,例如:select等。也可针对于字段值的改变触发一些特定的方法来实现特定的需求。再就是上移、下移、置顶、置底均用到了studentCode这个属性,那么这个属性应该保持其唯一性,这里没有为其增加唯一性校验,实际开发中应该注意。再就是习惯js的=赋值,在这里很多采用了$set去赋值,有时间我会单独聊一下这样赋值的原因。
最后希望大家开源自己,共同进步。