ElementUI左树右表checkbox的级联

该博客详细介绍了如何在Vue.js应用中结合Element UI库,实现树形结构的节点点击后加载表格数据,并确保点击树节点或表格复选框时,两侧的选中状态保持同步。通过监听`ids`数组变化来更新树形结构的选中状态,并在全选时选中所有表格项。此外,还实现了表格的行拖拽排序功能。
摘要由CSDN通过智能技术生成

先上效果图,这里打码不影响效果和实现, 我这里表格的数据是点击树的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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值