Bootstrap

el-tree懒加载前端实现动态变化

新项目需求:开发一个实时视频页面,左侧为视频播放部分,右侧为视频列表树,双击列表树的设备播放视频,并且判断播放状态回显到列表树上。后端没有接口可以反馈播放状态 (因为后端懒不愿写遍历的接口,如果可以后端遍历只需要改变树的数据就能动态刷新),所以只能用前端方法来实现列表树的播放状态

这时候就需要获取列表树的dom来进行递归遍历,因为是懒加载形成的树结构,所以需求获取整个dom结构来遍历改变样式

列表树html代码如下

<el-tree ref="tree" :data="treeData" node-key="id" :filter-node-method="filterNode" lazy :load="loadNode"
          highlight-current :props="defaultProps" @node-click="handleNodeClick">
          <div class="listItem" slot-scope="{ node, data }">
            <!-- 树结构最后一层 -->
            <div style="display: flex; align-items: center" v-if="node.level == 6">
              <!-- 设备播放状态 -->
              <div v-if="data.open" class="point" />
              <div v-else class="noPoint" />
              <!-- 设备在线状态 -->
              <div :class="data.devStatus == 1 ? 'icon-on' : 'icon-1'" />
            </div>
            <!-- 判断是否是可播放的设备 -->
            <span v-if="data.devCode" @dblclick="clkDb(data, node)" :title="data.name">{{ data.name }}</span>
            <span v-else :title="data.name">{{ data.name }}</span>
          </div>
        </el-tree>

data里写el-tree的自定义叶子结点,用来判断是否可以点击展开下一层

defaultProps: {
 children: "children",
 label: "name",
 isLeaf: "leaf",
},

页面布局如图

懒加载js代码如下

loadNode(node, reslove) {
      this.chooseNode = node;
      this.getTreeData(node, node.data.id, reslove);
    },
    async getTreeData(node, key, reslove) {
      if (node.level === 0) {
        this.treeLoading = true;
        const { value } = await getPlatInfo({});
        this.platInfo = value;
        let treeArr = [{ name: this.platInfo.platName }];
        reslove(treeArr);
        this.treeLoading = false;
      } else if (node.level === 1) {
        const { value } = await getResourceInfo(this.platInfo.platCode);
        let treeChildArr = value;
        reslove(treeChildArr, "treeChildArr");
      } else {
        // 最后一级节点
        if (node.data.resourceType == 4) {
          getMeasurementPointInfo(node.data.id).then((res) => {
            let arr = res.value;
            // 初始化视频播放状态,默认为未播放状态
            arr.forEach((item) => {
              item.open = false;
            });
            reslove(arr);
          });
        } else {
          getResourceInfo(node.data.id).then((res) => {
            reslove(res.value);
          });
        }
      }
    },

这里区分了node.level是因为后端给的树第一层的接口和第二层不一样,可以根据项目情况自己灵活修改区分层级懒加载接口,最后呈现的数据都会reslove()方法回显出来

注意reslove()里需要加上之前自定义叶子节点的格式,如果没有leaf值需要自己判断加上

下面是动态遍历部分js代码

// 双击列表播放视频
    clkDb(data, node) {
      if (data.devStatus != 1) {
        commonUtil.showTipInfo("选择的设备不在线,无法播放", "", "warning");
      } else {
        let result = this.videoPlay(
          data.devCode,
        );
        result.then((resultVlaue) => {
          this.removeRow(data);
        });
      }
    },
removeRow(row, close) {
      //递归el-tree节点
      let allNodesDom = this.$refs.tree.root.childNodes;
      function checkNodeDom(checkData) {
        let currentIndex = null;
        checkData.forEach((item, index) => {
          //最后一层
          if (item.childNodes.length == 0) {
            //对比需要对比的参数
            if (item.data.devCode == row.devCode) {
              // 关闭视频时传入参数
              if (close) {
                item.data.open = false;
              } else {
                // 重置状态为未播放状态再判断播放结果
                if (item.data.open == true) {
                  item.data.open = false;
                }
                if (item.data.devPtzIndex == row.devPtzIndex) {
                  currentIndex = index;
                  item.data.open = true;
                }
              }
            }
          } else if (item.childNodes.length > 0) {
            checkNodeDom(item.childNodes);
          }
        });
        return;
      }
      // 回调
      checkNodeDom(allNodesDom);
    },

这里通过递归遍历找到自己需要改变的节点数据,可以在遍历时调接口或者其他操作都可以,如果想改变节点数据可以判断节点level或者节点id再reslove()出来

在视频关闭的时候也需要调取removeRow()方法来遍历状态

总结:前端动态改变懒加载的树结构并不是很推荐,数据结构类尽量让后端来写比较好,有时候条件不允许也需要思考其他可以实现的办法进行开发。递归遍历部分的代码并没有精简优化,可以根据自己项目需求灵活修改。

;