目录
功能介绍
示例
代码
视图部分
逻辑部分
完整代码
功能介绍
本文介绍了如何在Vue.js框架下实现一个树状表格,其中支持选择子节点行的上下移动。通过这个功能,用户可以方便地改变子节点的顺序。代码示例和详细的实现步骤将展示如何使用Vue.js的相关特性和组件实现这个功能。通过本文的介绍,您可以轻松了解如何在您的Vue.js项目中应用这个功能,以满足您的特定需求。
示例
代码
视图部分
实现父节点选择的代码
在上次选中父节点的代码基础上加上操作行,生成上下移动的按钮:
<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
数组来寻找子行所属的父行。
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,
隐藏下移按钮。
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
数组来查找需要进行上移或下移操作的行,并进行相应的移动和调整索引的操作。最后,更新父级行的子行列表和相关数据。
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;}}})}
完整代码
<template><div><el-table v-loading="loading" :data="tableData" style="width: 100%;margin: 20px;" row-key="id" borderdefault-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>