Bootstrap

Element-UI实战系列:Tree组件的几种使用场景

前言

在使用开发项目时,引入了组件库,因为自己开发的部分,很多都是树形结构数据相关的,所以经常使用到组件,在好几次实现需求的过程中,遇到了很多难点,自己也是绞尽脑汁才解决的,这里就把遇到的几种使用场景,归纳总结一下。

一、普通模式 + 全部展开/全部收缩 + 全选/清空

这个主要是用来实现项目中权限功能部分,并且是在弹窗里面的,弹窗组件是使用里的组件,也就是说组件是包裹组件的,刚开始实现时,已经给组件设置了一个引用,也就是,但是一直显示报错,后来才发现是因为外层使用组件的缘故,组件的源码显示使用了,所以才获取不到,如图下所示: 

要获取,需要在下一个中才能获取到,代码如下所示:

this.$nextTick(() => {
    console.log(this.$refs.tree)
});

而且需要注意的是,在中使用组件,也会出现报错的问题,其原因,在之前的博文也说明过,不过这里还是把图贴出来,如下图所示:

所以要在中正确获取到,需要将其改为

效果图

实现过程

全部展开/全部收缩

    stretchClicked () {
      this.isStretch = !this.isStretch
      // tree为Tree组件的ref值,isexpand为true或false
      this.$nextTick(() => {
        for (var i = 0; i < this.$refs.tree.store._getAllNodes().length; i++) {
          this.$refs.tree.store._getAllNodes()[i].expanded = this.isStretch
        }
      })
    },

全选/清空

    selectClicked () {
      this.isSelect = !this.isSelect
      this.$nextTick(() => {
        for (var i = 0; i < this.$refs.tree.store._getAllNodes().length; i++) {
          this.$refs.tree.store._getAllNodes()[i].checked = this.isSelect
        }
      })
    }

因为组件里设置的原因,里的数据要有这个,理论上从服务器获取回来的数据不会有这个的,而且哪怕自己在本地模拟,要手动每个加上,然后还要唯一,还要排序,这个就很大工作量了,所以需要对数据进行处理,在初始化时,给里的每个加上,代码如下所示:

    // 给tree属性设置id
    setTreeDataNodeId (treeData) {
      var count = 1
      function traverse (data) {
        data.forEach(item => {
          item.id = count
          count = count + 1
          if (item.children) {
            traverse(item.children)
          }
        })
      }
      traverse(treeData)
    }

二、普通模式 + 单选

组件默认提供的是多选的,这边打算是实现单选功能,图标是在右侧,一开始实现的方式是在每一个节点加上一个字段,比如来设置选中和未选中的状态,但是发现在点击节点时,已经更改该节点的值了,但是视图并没有更新,原来在里初始化的时候,没有默认加上属性,我是在方法里,遍历加上的,所以没触发视图更新,其原因是只有当实例被创建时就已经存在于data中的 property 才是响应式的。也就是说如果你添加一个新的,比如这个,那么对的改动将不会触发任何视图的更新,详见Vue.js文档里部分,基于这个原因,如果要实现这个功能,难道要给这个手动加上么,如果数据量很大呢,或者是从服务器返回的数据呢,显然不现实,为了解决这个问题,我就想到,既然是单选,那可不可以直接使用组件提供的字段呢?

效果图

实现过程

其实主要还是实现上面全选功能时使用的那个方式,只要稍微变通下,就很明朗了,每次点击节点时,默认将组件里节点的状态重置为,然后将点击的节点设置为即可,代码如下所示:

    nodeClicked (data, node) {
      this.$nextTick(() => {
        // 每次点击节点时,默认将Tree组件的勾选状态设置为false
        for (var i = 0; i < this.$refs.tree.store._getAllNodes().length; i++) {
          this.$refs.tree.store._getAllNodes()[i].checked = false
        }
        // 给选中的节点checked设置为true
        this.$refs.tree.store._getAllNodes()[node.key - 1].checked = true
      })
    }

但是,通过观察,可以发现更好的实现方式,代码如下所示:

 nodeClicked (data, node) {
      this.$refs.tree.setCheckedKeys([])
      this.$refs.tree.store.currentNode.checked = true
    }

至于动态切换组件普通模式和懒加载模式,起先我是想着,但是发现没能成功,后来研究一番,才发现可以使用这个方式实现,代码如下所示:

this.$refs.tree.store.lazy = true

我本来是打算,将普通模式和懒加载模式结合起来,然后通过切换,也一样可以复用单选功能的,但是,研究了好久,还是觉得分开来写,分开来实现更为现实。

三、懒加载 + 单选

在实现普通模式+单选功能的时候,可以直接使用组件提供的字段,但在懒加载的情况下,发现实现很难,这样只能使用新加字段来实现了。

效果图

实现过程

的懒加载模式,使用起来要麻烦一点,实现单选功能,也就是通过新增的来切换勾选状态,首先要在组件加上懒加载模式,设置代码如下所示:


然后在方法里,当为时,新增一个根节点,同时设置,代码如下所示:

      // 初始化数据
      if (node.level === 0) {
        this.treeData = [{
          label: 'lazy-' + (node.level + 1),
          isChecked: false,
          children: []
        }]
        resolve(this.treeData)
        this.setTreeDataNodeId(this.treeData)
        return
      }

接着,当点击节点前面三角箭头,加载数据时,加上子节点,并且将,遍历设置值,加上延时加载,是为了模拟懒加载呈现的效果,代码如下所示:

      setTimeout(() => {
        const data = [
          {
            label: 'lazy-1-' + node.level,
            isChecked: false,
            children: []
          },
          {
            label: 'lazy-1-2',
            isChecked: false,
            children: [],
            leaf: true


          }]
        node.data.children = data
        resolve(data)
        this.setTreeDataNodeId(this.treeData)
      }, 500)

最后,就是点击节点,实现单选功能的处理,实现的逻辑也是一样的,每次点击该节点,就要将当前全部节点的重置为,然后,点击了这个节点,就将对应节点的设置为,这样就实现了单选效果,代码如下所示:

    nodeClicked (data, node) {
      this.setTreeDataNodeCheckedAllFalse(this.treeData)
      data.isChecked = true
    },
    setTreeDataNodeCheckedAllFalse (treeData) {
      function traverse (data) {
        data.forEach(item => {
          item.isChecked = false
          if (item.children && item.children.length > 0) {
            traverse(item.children)
          }
        })
      }
      traverse(treeData)
    }

四、普通模式/懒加载 + 添加/编辑/删除

这个场景工作中也遇到了,具体的需求就是,当鼠标移动到节点上时,右侧就会出现三个图标,分别是添加、编辑和删除,然后这三个功能就是对的操作了,只要上面几种场景都明白了,这个场景也不会难的,本来想着把这个实现一下,但是后来想想,意义不大,也就罢了。

写在最后

写这个东西其实有点痛苦,一来觉得很繁琐,二来虽然当时给自己带来了很大麻烦,但很担心可能是自己技术太菜才会觉得这个东西难,不过成长基于积累,从小事做起就好,也就看开了,希望自己能够坚持下来,不要轻视任何一个知识点。

示例代码: