问题形容

我的项目中应用树结构,次要信息个别在树的叶子节点上记录。然而有些状况下,后端是不把一些树叶子节点的状态信息做记录的,比方树叶子节点的状态(是否增加、是否珍藏什么的),后端只是把树结构所须要的数据返回给前端,至于状态什么的,前端须要去记录,而且状态的更改,也是须要前端去记录更改的
咱们先看一下我的项目的效果图:

效果图

功能分析

  • 当咱们点击左侧的叶子节点的时候,更改叶子节点成已增加的状态,同时将左侧的数据追加到右侧的表格中去:即:(点击叶子节点,更改叶子节点状态)
  • 当咱们再次点击叶子节点的时候,将叶子节点已增加的状态,批改成未增加的状态,同时删除右侧表格中的对应项:即:(点击叶子节点,更改叶子节点状态)
  • 当咱们删除右侧表格中的某一项时候,同时更改左侧的叶子节点的状态:即:(递归更改左侧树结构对应节点的状态)
本例是树组件懒加载的写法,对于树组件懒加载的写法,也能够参考我之前的一篇文章,传送门:https://segmentfault.com/a/11...

点击叶子节点,更改叶子节点状态

// 点击树组件节点上的增加或未增加按钮,更改树的增加未增加的状态,同时追加或删除右侧表格中对应的行的数据 changeStatus(node, data) {    // console.log("data是点击的这个树节点所绑定的数据", data);    if (data.status == "0") {      data.status = "1"; // 这里咱们能够间接更改树节点上的对应数据,便会失效,未增加变成已增加      this.tableData.push(data); // 追加进右侧表格    } else if (data.status == "1") {      data.status = "0"; // 已增加变成未增加      this.tableData.forEach((item, index) => {        // 同时,依据id去删除掉右侧的数据        if (item.id == data.id) {          this.tableData.splice(index, 1);        }      });    }  }
留神html中的这个changeStatus办法是点击按钮的高阶函数的写法,这样:@click="() => changeStatus(node, data)"

递归更改左侧树结构对应节点的状态

// 第一步:依据删除或者id,而后依据id递归更改树节点状态字段// 第二步:把表格中的数据删除即可removeRow(row) {  // console.log("行数据", row.id);  // 获取tree的所有的node节点数组(DOM节点),这里是两个数组,对应的就是西游记和三国演义的最外层的数组()  let allNodesDom = this.$refs.myTree.root.childNodes;  console.log("node节点树结构", allNodesDom);  function bianli(checkedData) {    for (const i in checkedData) {      // 阐明到最内层了      if (checkedData[i].childNodes.length == 0) {        // 到最内层当前,就看看对应的id,是否与移除行的id统一        if (checkedData[i].data.id == row.id) {          // 若id统一,就更改树组件的最内层节点的数据即可          checkedData[i].data.status = "0";          break;        }      } else if (checkedData[i].childNodes.length > 0) {        // 阐明没到最内层,那就持续递归调用本人,持续找        bianli(checkedData[i].childNodes);      }    }    return;  }  bianli(allNodesDom); // 递归调用,更改数据  // 同时依据id删除右侧的表格对应的行  this.tableData.forEach((item, index) => {    if (item.id == row.id) {      this.tableData.splice(index, 1);    }  })}

代码附上

<template>  <div class="box">    <!-- 左侧树局部 -->    <div class="leftBox">      <el-tree ref="myTree" :props="props" :load="loadNode" lazy node-key="id">        <span slot-scope="{ node, data }">          <i            class="el-icon-folder-opened"            style="color: #448ff7"            v-show="node.isLeaf !== true"          ></i>          <!-- <span style="padding-left: 8px">{{ node.label }}</span> -->          <span style="padding-left: 8px">{{ data.name }}</span>          <el-button            style="margin-left: 12px"            size="small"            type="text"            v-show="node.isLeaf === true"            @click="() => changeStatus(node, data)"          >            <span :class="{ highLightTree: data.status == '0' }">{{              data.status == "0" ? "未增加" : "已增加"            }}</span>          </el-button>        </span>      </el-tree>    </div>    <!-- 右侧表格局部 -->    <div class="rightBox">      <el-table        :data="tableData"        border        style="width: 100%"        :header-cell-style="{          height: '48px',          background: '#FAFAFA',          color: '#333333',          fontWeight: 'bold',        }"      >        <el-table-column prop="id" label="id编号"></el-table-column>        <el-table-column prop="name" label="姓名"></el-table-column>        <el-table-column prop="home" label="地址"></el-table-column>        <el-table-column label="操作">          <template slot-scope="scope">            <el-button              @click="removeRow(scope.row)"              type="danger"              plain              size="small"              >移除</el-button            >          </template>        </el-table-column>      </el-table>    </div>  </div></template><script>export default {  data() {    return {      props: {        label: "name",        isLeaf: "isLeaf",      },      tableData: [],    };  },  methods: {    //初始加载最外层节点    loadNode(node, resolve) {      // 点击节点加载相应节点的数据      if (node.level == 0) {        this.loadfirstnode(resolve);      }      //如果开展其余级节点,动静从后盾加载下一级节点列表      if (node.level >= 1) {        this.loadchildnode(node, resolve);      }    },    //加载第一级节点    async loadfirstnode(resolve) {      let params = {        level: 0,      };      const res = await this.$api.getTreeData(params);      return resolve(res.data);    },    //加载节点的子节点汇合    async loadchildnode(node, resolve) {      // console.log("超过二级的", node, node.level);      let params = {        id: node.key,      };      const res = await this.$api.getTreeChildData(params);      return resolve(res.data);    },    // 点击树组件节点上的增加或未增加按钮,更改树的增加未增加的状态,同时追加或删除右侧表格中对应的行的数据    changeStatus(node, data) {      // console.log("data是点击的这个树节点所绑定的数据", data);      if (data.status == "0") {        data.status = "1"; // 这里咱们能够间接更改树节点上的对应数据,便会失效,未增加变成已增加        this.tableData.push(data); // 追加进右侧表格      } else if (data.status == "1") {        data.status = "0"; // 已增加变成未增加        this.tableData.forEach((item, index) => {          // 同时,依据id去删除掉右侧的数据          if (item.id == data.id) {            this.tableData.splice(index, 1);          }        });      }    },    // 第一步:依据删除或者id,而后依据id递归更改树节点状态字段    // 第二步:把表格中的数据删除即可    removeRow(row) {      // console.log("行数据", row.id);      // 获取tree的所有的node节点数组(DOM节点),这里是两个数组,对应的就是西游记和三国演义的最外层的数组()      let allNodesDom = this.$refs.myTree.root.childNodes;      console.log("node节点树结构", allNodesDom);      function bianli(checkedData) {        for (const i in checkedData) {          // 阐明到最内层了          if (checkedData[i].childNodes.length == 0) {            // 到最内层当前,就看看对应的id,是否与移除行的id统一            if (checkedData[i].data.id == row.id) {              // 若id统一,就更改树组件的最内层节点的数据即可              checkedData[i].data.status = "0";              break;            }          } else if (checkedData[i].childNodes.length > 0) {            // 阐明没到最内层,那就持续递归调用本人,持续找            bianli(checkedData[i].childNodes);          }        }        return;      }      bianli(allNodesDom); // 递归调用,更改数据      // 同时依据id删除右侧的表格对应的行      this.tableData.forEach((item, index) => {        if (item.id == row.id) {          this.tableData.splice(index, 1);        }      })    }      },};</script>
对于本篇文章的前后端的残缺代码,欢送到我的Gitee上下载哈,后端用express模仿数据接口返回前端,传送门如下 https://gitee.com/ah-shuai/de...