公司新来了一个需求:表格最左侧为新增,然后分类可以展开,子列表超过5条进行折叠收缩
视频操作顺序依次为:展开分类=> 展开更多=> 删除 => 新增 => 编辑=> 设置生效与失效
录制的gif
重要难点:新增和删除时,会对折叠功能造成影响
其他难点:
- 新增列必须使用多选框改造, 否则会被el-table认成展开图标列
- 每次点击都需要通过id找到当前数据,因为树表格会把坐标打乱
- 将子级数量超过5条后的全部折叠起来
- 需要复制一个表格数据出来,需要每次新增或删除需要重排下索引值和折叠功能
- 点击新增使当前的分类展开后,需要将:expand-row-keys数组置空,否则新增其他分类时,会将上一个分类也给展开
因为代码量不算多,我直接简化拿了过来,并加上注释
<el-table
v-loading="loading"
element-loading-background="rgba(255, 255, 255, 0.7)"
:data="tableData"
class="tableBox"
border
style="width: 100%"
:row-class-name="tableRowClassName"
:row-key="getRowKeys"
:span-method="arraySpanMethod"
:expand-row-keys="expands"
:tree-props="{children: 'children'}"
@selection-change="handleSelectionChange">
<!-- <el-table-column align="center" type="selection" class-name="DisabledSelectionAll" label-class-name="DisabledSelection" width="55"></el-table-column> -->
<el-table-column align="center" type="selection" label-class-name="DisabledSelection" width="50">
<template slot-scope="scope">
<span @click="addRow(scope.row)" v-if="scope.row.type == 'father'" class="hand">+</span>
</template>
</el-table-column>
<el-table-column align="left" prop="post" label="适用岗位" width="130"> </el-table-column>
<el-table-column align="center" prop="index" label="序号" width="50"> </el-table-column>
<el-table-column align="center" prop="address" label="工作内容" width="180">
<template slot-scope="scope">
<div v-if="!scope.row.type">
<span v-if="scope.row.modify">{{scope.row.name}}</span>
<el-input v-else v-model="scope.row.name" type="text" />
</div>
</template>
</el-table-column>
<el-table-column align="center" label="创建日期">
<template slot-scope="scope" >
<span v-if="!scope.row.type">{{scope.row.date}}</span>
<el-button v-if="scope.row.type === 'shrink'" type="text" @click="handleShrink(scope.row)">{{scope.row.date}}</el-button>
</template>
</el-table-column>
<el-table-column align="center" prop="requency" label="频率">
<template slot-scope="scope" v-if="!scope.row.type">
<span v-if="scope.row.modify">{{optionsFrequency[Number(scope.row.requency)-1].label}}</span>
<el-select v-else v-model="scope.row.requency" placeholder="请选择">
<el-option
v-for="item in optionsFrequency"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column align="center" label="操作">
<template slot-scope="scope" v-if="!scope.row.type">
<el-button v-if="scope.row.modify" type="text" @click="handleEdit(scope.row, true)">修改</el-button>
<el-button v-else type="text" @click="handleSave(scope.row)">保存</el-button>
<el-button v-if="scope.row.takeEffect"@click="handleTakeEffect(scope.row)" type="text">生效</el-button>
<el-button v-else type="text"@click="handleTakeEffect(scope.row)">失效</el-button>
<el-button @click="handleDelete(scope.row)" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
js
moment插件和lodash可以不用,自己用其他方法
<script>
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
export default {
data() {
return {
loading: false,
num: 10000,
tableData: [],
tableDataCopy: [],
optionsFrequency: [
{
value: '1',
label: '工作日'
},
{
value: '2',
label: '每周一'
},
{
value: '3',
label: '每周二'
},
{
value: '4',
label: '每周三'
},
{
value: '5',
label: '每周四'
},
{
value: '6',
label: '每周五'
},
{
value: '7',
label: '每月初'
},
{
value: '8',
label: '每周五'
},
{
value: '9',
label: '每月末'
},
{
value: '10',
label: '不定期'
},
],
expands: [],
};
},
created(){
this.start()
},
mounted() {
// 默认展开第0个
this.expands = [this.tableData[0].id.toString()]
this.$nextTick(() => {
this.expands = []
})
},
methods: {
start(){
this.tableData = [
{
id: 1,
post: 'OPM运营岗',
type:'father',
takeEffect: false,
children: [
{
id: 2,
date: '2016-05-01',
name: '王小虎',
requency: '2',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '3',
}, {
id: 3,
date: '2016-05-01',
name: '王小虎',
requency: '10',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
},
{
id: 12,
date: '2016-05-01',
name: '王小虎',
requency: '2',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '3',
}, {
id: 13,
date: '2016-05-01',
name: '王小虎',
requency: '10',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
},
{
id: 14,
date: '2016-05-01',
name: '王小虎',
requency: '2',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '3',
}, {
id: 15,
date: '2016-05-01',
name: '王小虎',
requency: '10',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
}
]
},
{
id: 4,
post: '参数录入岗',
type:'father',
children: [
{
id: 5,
date: '2016-05-01',
name: '王小虎',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '3',
}, {
id: 6,
date: '2016-05-01',
name: '王小虎',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
}
]
},
{
id: 7,
post: '基金会计港',
type:'father',
children: [
{
id: 31,
date: '2016-05-01',
name: '王小虎',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '2',
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
requency: '4',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
},
{
id: 33,
date: '2016-05-01',
name: '王小虎',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '2',
}, {
id: 34,
date: '2016-05-01',
name: '王小虎',
requency: '4',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
},
{
id: 35,
date: '2016-05-01',
name: '王小虎',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄',
state: '2',
}, {
id: 36,
date: '2016-05-01',
name: '王小虎',
requency: '4',
takeEffect: false,
address: '上海市普陀区金沙江路 1519 弄',
state: '1',
},
]
},
{
id: 10,
name: '王小虎',
state: '3',
post: '头寸管理岗',
requency: '6',
type:'father',
takeEffect: true,
address: '上海市普陀区金沙江路 1516 弄',
children:[
{
id: 41,
date: '2016-05-01',
name: '王小虎1',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄1',
state: '3',
}, {
id: 42,
date: '2016-05-01',
name: '王小虎2',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄2',
state: '1',
},
{
id: 43,
date: '2016-05-01',
name: '王小虎3',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄3',
state: '3',
}, {
id: 44,
date: '2016-05-01',
name: '王小虎4',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄4',
state: '1',
},
{
id: 45,
date: '2016-05-01',
name: '王小虎5',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄5',
state: '3',
}, {
id: 46,
date: '2016-05-01',
name: '王小虎6',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄6',
state: '1',
},
{
id: 47,
date: '2016-05-01',
name: '王小虎7',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄7',
state: '3',
}, {
id: 48,
date: '2016-05-01',
name: '王小虎8',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄8',
state: '1',
},
{
id: 49,
date: '2016-05-01',
name: '王小虎9',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄9',
state: '3',
}, {
id: 410,
date: '2016-05-01',
name: '王小虎10',
requency: '3',
takeEffect: true,
address: '上海市普陀区金沙江路 1519 弄10',
state: '1',
}
]
},
]
this.tableDataCopy = cloneDeep(this.tableData)
this.serialnumber()
this.tableShrink()
},
// 设置序号
serialnumber(){
this.tableData.forEach((item,index) => {
if(item.children && item.children.length){
item.children.forEach((item2, index2) => {
// 设置序号
if(item.type !== 'shrink'){ // 收缩键
this.$set(item2, 'index', index2 + 1)
}else{
this.$set(item2, 'index', '')
}
// 当前为保存状态(无可编辑需求可以忽略)
this.$set(item2, 'modify', true)
})
}
})
},
// 展开/收缩
tableShrink(){
this.tableData.forEach(item => {
if(item.children.length > 5){
const newChildren = item.children.splice(5, item.children.length)
this.$set(item, 'newChildren', newChildren)
this.num ++
item.children.push({
id: this.num,
type:'shrink',
date:'展开》'
})
}
})
},
// 获取row的key值
getRowKeys(row) {
return row.id;
},
handleShrink(row, indexArr=null){
const arr = indexArr? indexArr : this.ObtainIndex(row.id)
if(row.date == '展开》'){
// 取出被折叠的数据
const oldChildren = this.tableData[arr[0]].newChildren.splice(0, this.tableData[arr[0]].newChildren.length)
// 取出最后的折叠按钮
const Shrink = this.tableData[arr[0]].children.splice(this.tableData[arr[0]].children.length-1, 1)
this.$nextTick(() => {
this.tableData[arr[0]].children.push(...oldChildren)
Shrink[0].date = '收起》'
this.tableData[arr[0]].children.push(...Shrink)
})
}else{
// 需要折叠的数据
const newChildren = this.tableData[arr[0]].children.splice(5, this.tableData[arr[0]].children.length -6)
this.tableData[arr[0]].newChildren = newChildren
// 最后的折叠按钮
this.tableData[arr[0]].children[this.tableData[arr[0]].children.length-1].date = '展开》'
}
},
// 合并
arraySpanMethod({ row, column, rowIndex, columnIndex }){
// 合并展开/收缩
// if(row.type === 'shrink'){
// if (columnIndex === 4) {
// return {
// rowspan: 1,
// colspan: 6
// }
// }
// }
// 合并岗位
if(row.type === 'father'){
if (columnIndex === 1) {
return {
rowspan: 1,
colspan: 6
}
}
}
},
// 新增
addRow(row){
const index = this.tableData.findIndex(item => {
return item.id === row.id
})
console.log(row.id)
this.tableDataCopy[index].children.unshift({
id: Date.now(),
index: 1,
post:'',
name:'',
date:moment(new Date()).format("YYYY-MM-DD"),
requency:'1',
modify: false,
takeEffect: false,
})
this.tableData = cloneDeep(this.tableDataCopy)
this.serialnumber()
this.tableShrink([index])
this.expands = [this.tableData[index].id.toString()]
this.$nextTick(() => {
this.expands = []
})
},
// 获取坐标
ObtainIndex(id){
const indexArr = []
for(let i = 0;i < this.tableData.length;i ++){
if(!(this.tableData[i].children && this.tableData[i].children.length)) continue
const itemIndex = this.tableData[i].children.findIndex(item => {
return item.id == id
})
if(itemIndex > -1){
indexArr.push(i)
indexArr.push(itemIndex)
break
}
}
return indexArr
},
// 编辑
handleEdit(row){
const arr = this.ObtainIndex(row.id)
this.tableData[arr[0]].children[arr[1]].modify = !this.tableData[arr[0]].children[arr[1]].modify
},
// 保存
handleSave(row){
this.loading = true
const that = this
// ajax
setTimeout(() => {
this.handleEdit(row)
that.loading = false
},300)
},
// 生效/失效
handleTakeEffect(row){
const arr = this.ObtainIndex(row.id)
this.loading = true
// ajax
setTimeout(() => {
this.loading = false
this.tableData[arr[0]].children[arr[1]].takeEffect = !this.tableData[arr[0]].children[arr[1]].takeEffect
},300)
},
// 删除
handleDelete(row){
this.loading = true
setTimeout(() => {
this.loading = false
const arr = this.ObtainIndex(row.id)
this.tableData = []
this.tableDataCopy[arr[0]].children.splice(arr[1], 1)
this.tableData = cloneDeep(this.tableDataCopy)
this.serialnumber()
this.tableShrink(arr)
}, 300)
},
// 设置失效行的class
tableRowClassName({row, rowIndex}) {
if (!row.type && row.takeEffect === false) {
return 'warning-row';
}
return '';
},
}
};
</script>
css
<style lang='scss' scoped>
.hand{
cursor: pointer;
}
.el-table /deep/ .DisabledSelection .cell .el-checkbox__inner {
display: none;
position: relative;
}
/*表格全选框改为:新增*/
.el-table /deep/ .DisabledSelection .cell:before {
content: "新增";
position: absolute;
left: 14px;
}
.tableBox /deep/ .el-input__inner{
// border: none;
width: 86px;
}
</style>