目录
功能介绍
本文介绍了如何在Vue.js框架下实现一个树状表格,其中支持选择子节点行的上下移动。通过这个功能,用户可以方便地改变子节点的顺序。代码示例和详细的实现步骤将展示如何使用Vue.js的相关特性和组件实现这个功能。通过本文的介绍,您可以轻松了解如何在您的Vue.js项目中应用这个功能,以满足您的特定需求。
示例
代码
视图部分
在上次选中父节点的代码基础上加上操作行,生成上下移动的按钮:
html
<el-table-column align="center">
<template slot-scope="scope" v-if="!scope.row.children">
<el-button v-show="!validateOperate(scope.row, 'up')" size="mini" icon="el-icon-top" plain
@click="handleSort(scope.row, 'up')">
</el-button>
<el-button v-show="!validateOperate(scope.row, 'down')" size="mini" icon="el-icon-bottom" plain
@click="handleSort(scope.row, 'down')"></el-button>
</template>
</el-table-column>
新增列定义,用于显示上移和下移按钮。<template> 标签中定义了使用 slot-scope 来访问作用域插槽,在这个作用域下,使用了两个 <el-button> 元素来展示上移和下移按钮。为了使第一行与最后一行只有下移或上移,这里通过绑定 v-show 来控制按钮的显示与隐藏,根据 validateOperate() 方法的返回值确定按钮是否可见。@click 侦听器则会触发 handleSort() 方法来完成所在行的移动。
逻辑部分
组件数据和选中父节点的代码相同,获取tableData后,如果没有index,则自己遍历加上该属性。
methods
对象新增方法:
getParent(id)
方法用于获取拥有指定子行id
的父级行,它通过遍历this.tableData
数组来寻找子行所属的父行。
javascript
getParent(id) {
let result = [];
this.tableData.some(item => {
item.children.some(d => {
if (d.id == id) result = item;
})
});
return result;
}
validateOperate(row, type)
方法用于根据指定的操作类型(上移或下移)检查当前行是否可进行该操作。首先判断是否最内层的子树,对于上移操作,当前行的索引为0时返回true,
隐藏上移按钮;对于下移操作,当前行的索引等于自身所处children数组的长度减1时返回true,
隐藏下移按钮。
javascript
validateOperate(row, type) {
if (!row.children) {
if (type == 'up' && row.index == 0) {
return true;
}
else if (type == 'down') {
return this.getParent(row.id).children.length - 1 == row.index;
}
else {
return false;
}
}
}
handleSort(row, type)
方法用于处理行的上移和下移操作。它首先获取该行的父级行和父级行的 ID,并定义一个标志变量downFlag
。然后通过遍历parent.children
数组来查找需要进行上移或下移操作的行,并进行相应的移动和调整索引的操作。最后,更新父级行的子行列表和相关数据。
javascript
handleSort(row, type) {
let parent = this.getParent(row.id);
let parentId;
let downFlag = true;
this.tableData.forEach(item => {
if (item.children === parent) parentId = item.id;
});
console.log(parent);
parent.children.some(item => {
if (type == 'up') {
if (item.index == row.index - 1) {
parent.children.splice(row.index, 1);
parent.children.splice(item.index, 0, row);
parent.children.forEach((child, index) => child.index = index);
this.tableData.forEach(data => {
if (data.id === parentId) data.children = parent.children;
});
}
} else if (type == 'down' && downFlag) {
if (item.index == row.index + 1) {
parent.children.splice(row.index, 1);
parent.children.splice(item.index, 0, row);
parent.children.forEach((child, index) => child.index = index);
this.tableData.forEach(data => {
if (data.id === parentId) data.children = parent.children;
});
downFlag = false;
}
}
})
}
完整代码
javascript
<template>
<div>
<el-table v-loading="loading" :data="tableData" style="width: 100%;margin: 20px;" row-key="id" border
default-expand-all :tree-props="{ children: 'children' }">
<el-table-column width="60" align="center">
<template slot="header" slot-scope="scope">
<el-checkbox :indeterminate="isIndeterminate" v-model="isFullChecked" @change="checkAllChange">
</el-checkbox>
</template>
<template slot-scope="{row}" v-if="row.children">
<el-checkbox :indeterminate="row.isIndeterminate" :value="row.checked" @change="checkRowChange(row)">
</el-checkbox>
</template>
</el-table-column>
<el-table-column prop="series" label="系列" align="center"></el-table-column>
<el-table-column prop="num" label="编号" align="center"></el-table-column>
<el-table-column prop="name" label="名字" align="center"></el-table-column>
<el-table-column align="center">
<template slot-scope="scope" v-if="!scope.row.children">
<el-button v-show="!validateOperate(scope.row, 'up')" size="mini" icon="el-icon-top" plain
@click="handleSort(scope.row, 'up')">
</el-button>
<el-button v-show="!validateOperate(scope.row, 'down')" size="mini" icon="el-icon-bottom" plain
@click="handleSort(scope.row, 'down')"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
isFullChecked: false,
isIndeterminate: false,
loading: true,
tableData: []
}
},
mounted() {
this.getList()
},
watch: {
tableData() {
this.isFullChecked = false;
this.isIndeterminate = false;
}
},
methods: {
getList() {
const tableData = [
{
id: 1,
series: 'DDLC',
children: [
{
id: 11,
num: '1',
name: 'monika',
index: 0,
},
{
id: 12,
num: '2',
name: 'nasuki',
index: 1,
},
{
id: 13,
num: '3',
name: 'sayori',
index: 2,
},
{
id: 14,
num: '4',
name: 'yuri',
index: 3,
}
]
},
{
id: 2,
series: 'Bloom Into You',
children: [
{
id: 21,
num: '11',
name: 'nanami',
index: 0,
},
{
id: 22,
num: '12',
name: 'yuu',
index: 1,
}
]
},
];
tableData.forEach(item => {
item.checked = false;
item.isIndeterminate = false;
})
this.tableData = tableData;
this.total = this.tableData.length;
this.loading = false;
},
checkAllChange() {
const recursionSetChecked = (item, checked) => {
item.checked = checked;
item.isIndeterminate = false;
}
this.isIndeterminate = false;
this.tableData.forEach(item => recursionSetChecked(item, this.isFullChecked));
},
checkRowChange(data) {
data.checked = !data.checked;
const recursion = node => {
if (node.children && node.children.length > 0)
node.isIndeterminate = false;
return node;
};
this.tableData.forEach(item => recursion(item));
if (this.tableData.every(item => item.checked)) {
this.isFullChecked = true;
}
else if (this.tableData.every(item => !item.checked)) {
this.isFullChecked = false;
}
this.isIndeterminate = this.tableData.some(item => item.isIndeterminate)
? true
: this.tableData.some(item => !item.checked) && this.tableData.some(item => item.checked);
},
getParent(id) {
let result = [];
this.tableData.some(item => {
item.children.some(d => {
if (d.id == id) result = item;
})
});
return result;
},
validateOperate(row, type) {
if (!row.children) {
if (type == 'up' && row.index == 0) {
return true;
}
else if (type == 'down') {
return this.getParent(row.id).children.length - 1 == row.index;
}
else {
return false;
}
}
},
handleSort(row, type) {
let parent = this.getParent(row.id);
let parentId;
let downFlag = true;
this.tableData.forEach(item => {
if (item.children === parent) parentId = item.id;
});
console.log(parent);
parent.children.some(item => {
if (type == 'up') {
if (item.index == row.index - 1) {
parent.children.splice(row.index, 1);
parent.children.splice(item.index, 0, row);
parent.children.forEach((child, index) => child.index = index);
this.tableData.forEach(data => {
if (data.id === parentId) data.children = parent.children;
});
}
} else if (type == 'down' && downFlag) {
if (item.index == row.index + 1) {
parent.children.splice(row.index, 1);
parent.children.splice(item.index, 0, row);
parent.children.forEach((child, index) => child.index = index);
this.tableData.forEach(data => {
if (data.id === parentId) data.children = parent.children;
});
downFlag = false;
}
}
})
}
}
}
</script>