先上效果图,这里打码不影响效果和实现, 我这里表格的数据是点击树的node后触发向后台数据请求,这里刚进来就没有数据。
点击树的node后,右边表格就有数据,这些都不本文要实现的目的,本文要实现的是点击左侧的checkbox,右侧的checkbox会被选中,当点击下一个树node时,上一个树node的状态要保持。点击左侧全选框时,右侧所有checkbox会被选中。


具体思路:
借用this.$refs.taskTable.selection这个数组,如果这个数组中表格某一行的对象,则表格的checkbox会被勾选,所以我往这个数组中添加对象,就会使得表格对应的checkbox被勾选,如果是手动点击表格的checkbox,这个数组中的对象会自动被删除。 由于没有点击到的树node表格数据还没加载出来,所以我在创建这个页面的时候就把node对应表格数据全部获取了出来,这里面的this.idMapping数组就是提前获取到的map,key为树node id,value为表格数据。
具体实现:这是核心代码,不能直接运行
<template>
<div >
<div style="margin-top: 10px">
<el-row :gutter="5" class="mb8">
<el-col :span="4">
<el-input
placeholder="输入关键字进行过滤"
v-model="filterText">
</el-input>
<el-tree
ref="tree"
show-checkbox
:data="myTreeData"
:props="defaultProps"
v-loading="treeLoading"
node-key="testObjectId"
default-expand-all
highlight-current
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
>
</el-tree>
</el-col>
<el-col :span="20">
<el-table ref="taskTable"
:data="taskList"
:row-key="getRowKey"
height="650"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
v-loading="loading"
id="out-table"
stripe>
<el-table-column type="selection" width="35" align="center" :reserve-selection="true"></el-table-column>
<el-table-column label="列名1" width="120" align="center" >
<template slot-scope="scope">
</template>
</el-table-column>
<el-table-column label="列名2" align="center" >
</el-table-column>
<el-table-column label="列名3" align="center" >
</el-table-column>
<el-table-column label="列名4" align="center" >
</el-table-column>
<el-table-column label="列名5" align="center" >
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[20,40,60,total]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import {getTaskById, getTreeData,getTmpTask,sortTask,getIdMapping} from "@/api/testPlan";
import XLSX from "xlsx";
import FileSaver from "file-saver";
import Sortable from 'sortablejs'
export default {
name: "taskRecord",
props: {
cycleId: {
type: Number,
default: 0
}
},
data(){
return{
listQuery: {
pageNum: 1,
pageSize: 20,
},
filterText:'',
myTreeData:[],
taskList: [],
total:0,
treeLoading:false,
loading:false,
drawerVisible:false,
isMoved:false,
myTask:[],
ids: [],
indexs: [],
pcList:[],
idMapping:[],
testObjectList:[],
testobjectId:null,
defaultProps: {
children: 'children',
label: 'label'
}
}
},
created() {
//获取树node对应的表格数据
this.getTreeData();
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
//监听ids的变化,这样点击表格的checkbox,树的checkbox也会变化
ids:{
deep: true,
handler(val){
var res = new Array();
//遍历this.idMapping,删除树状结构没有选择的checkbox
var keys = Object.keys(this.idMapping);
keys.forEach(key => {
for(var i=0;i<this.idMapping[key].length;i++){
if(this.ids.includes(this.idMapping[key][i].id)){
res.push(Number(key));
break;
}
}
});
this.$refs.tree.setCheckedKeys(res)
}
},
},
mounted() {
this.rowDrop();
},
methods:{
//这是table的行拖拽效果,与本案例无关
rowDrop() {
const tbody = document.querySelector('.el-table__body-wrapper tbody');
const _this = this;
Sortable.create(tbody, {
animation:100,
onEnd({ newIndex, oldIndex }) {
_this.isMoved = true;
//删除当前移动的数据
const currRow = _this.taskList.splice(oldIndex, 1)[0];
//将当前移动数据放入新的位置
_this.taskList.splice(newIndex, 0, currRow);
}
})
},
//提交拖拽后的排序
submitSort(){
var tmpids = [];
this.taskList.forEach((item,index,array) =>{
tmpids.push(item.id);
});
sortTask(tmpids).then(result => {
this.$message({
message: '提交成功',
type: 'success',
duration: 2000
});
this.getTask();
this.isMoved = false;
})
},
//取消拖拽排序
CancelSort(){
this.getTask();
this.isMoved = false;
},
//页面初始化时获取树结构数据,并获取树结构和表格数据的对应关系
getTreeData(){
this.treeLoading = true;
getTreeData(this.cycleId).then(result => {
this.myTreeData = result.data;
});
getIdMapping(this.cycleId).then(result => {
this.idMapping = result.data
});
this.treeLoading = false;
},
handleNodeClick(obj,node,arr){
if(node.isLeaf){
this.testobjectId = node.data.testObjectId;
this.getTask();
}
},
//点击树node后触发向后台获取数据
getTask(){
this.loading = true;
this.listQuery.cycleId = this.cycleId;
this.listQuery.testobjectId = this.testobjectId;
getIdMapping(this.cycleId).then(result => {
this.idMapping = result.data
});
getTmpTask(this.listQuery).then(result => {
this.taskList = result.data.list;
this.total = result.data.total;
this.pageSize = result.data.pageSize;
this.loading = false;
});
},
//重置搜索
resetQuery() {
this.listQuery.pcIp = '';
this.listQuery.testobjectName = '';
this.listQuery.result = null;
},
//输出对象在JSON数组中的位置
objIndex(jsonArr, obj){
for(var i=0; i< jsonArr.length; i++){
if(jsonArr[i].id == obj.id){
return i;
}
}
return -1;
},
//表格的checkbox发生变化时,这个数组this.$refs.taskTable.selection的值就会发生变化,并把这个值里面的id赋值到ids中,使用就会触发ids的监听
handleSelectionChange() {
this.ids= [];
this.$refs.taskTable.selection.forEach(item => {
this.ids.push(item.id)
})
},
//点击表格行时触发表格checkbox勾选和取消
handleRowClick(row, event, column){
this.$refs.taskTable.toggleRowSelection(row);
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getTask();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getTask();
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
getRowKey(row){
return row.id;
},
//树形checkbox点击事件
handleCheckChange(obj,selfIsChecked,childIsChecked){
var node = this.$refs.tree.getNode(obj.testObjectId);
if(node !== null && node.isLeaf){
if(node.checked){
//前盘下有没有任务被选择
var tmpflag = false;
this.idMapping[obj.testObjectId].forEach(item =>{
var res = this.objIndex(this.$refs.taskTable.selection, item);
if(res >= 0){
tmpflag = true;
}
});
if(!tmpflag){ //当前盘下没有任务被选择
this.idMapping[obj.testObjectId].forEach(item =>{
this.$refs.taskTable.selection.push(item);
});
}
}else{
//如果是取消选择
this.idMapping[obj.testObjectId].forEach(item =>{
var res = this.objIndex(this.$refs.taskTable.selection, item);
if(res >= 0){
this.$refs.taskTable.selection.splice(res,1);
}
});
}
if(this.testobjectId === node.data.testObjectId){ //用于当前窗口就在当前节点
this.getTask()
}
}
},
exportExcel() {
/* 转换成excel时,使用原始的格式,解决数字列自动转科学计数法问题 */
let xlsxParam = { raw: true };
/* 从表生成工作簿对象 */
let wb = XLSX.utils.table_to_book(document.querySelector("#out-table"), xlsxParam);
/* 获取二进制字符串作为输出 */
let wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array"
});
try {
FileSaver.saveAs(
//Blob 对象表示一个不可变、原始数据的类文件对象。
//Blob 表示的不一定是JavaScript原生格式的数据。
//File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
//返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。
new Blob([wbout], { type: "application/octet-stream" }),
//设置导出文件名称
"执行记录.xlsx"
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
}
return wbout;
}
},
}
</script>
<style scoped>
</style>
该博客详细介绍了如何在Vue.js应用中结合Element UI库,实现树形结构的节点点击后加载表格数据,并确保点击树节点或表格复选框时,两侧的选中状态保持同步。通过监听`ids`数组变化来更新树形结构的选中状态,并在全选时选中所有表格项。此外,还实现了表格的行拖拽排序功能。
5996

被折叠的 条评论
为什么被折叠?



