阅读 6017

使用element-ui的el-tree组件入坑讲解之setCheckedKeys

1、前提基础

  • 掌握vue、element-ui相关前端知识,若有还没掌握的童鞋可以先去看我的vue全家桶一文:juejin.im/post/5bfe4a…

2、业务场景描述

  1. 假设现在我们有一个人员列表,需要给每个人配置特定的权限来限制哪些人可以干些什么:

3、代码

  1. 新建AuthTree.vue页面:
<template>
  <div class="auth_tree">
    <el-table
      :data="listData"
      border
      style="width: 100%;">
      <el-table-column label="ID" prop="id">  
      </el-table-column>
      <el-table-column label="姓名" prop="name">  
      </el-table-column>
      <el-table-column label="性别" prop="sex">  
      </el-table-column>
      <el-table-column label="权限配置">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" @click="opetation(scope.row.auth)">配置</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-dialog
      :visible.sync="dialogVisible"
      title="配置权限"
      center
      width="600px"
      @close="closeDialog">
      <div class="dialog_main_content">
        <el-tree
          ref="tree"
          :data="treeData"
          :expand-on-click-node="false"
          :show-checkbox="true"
          node-key="id"
          default-expand-all
          @check="currentChecked"/>
      </div>
      <div class="dialog_footer">
        <el-button @click="cancel">取 消</el-button>
        <el-button type="primary" @click="confirm">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
复制代码
  1. 模拟数据data部分:
 data() {
    return {
      listData: [
        {
          id: 1,
          name: 'syz',
          sex: '男',
          auth: [1, 2]
        },
        {
          id: 2,
          name: 'lyy',
          sex: '女',
          auth: [11, 21]
        },
        {
          id: 3,
          name: 'yf',
          sex: '男',
          auth: [211, 212]
        },
        {
          id: 4,
          name: 'xkl',
          sex: '女',
          auth: [211]
        },
        {
          id: 5,
          name: 'txl',
          sex: '女',
          auth: [221]
        }
      ],
      dialogVisible: false,
      treeData: [
        {
          id: 1,
          label: '一级 1',
          children: [
            {
              id: 11,
              label: '二级 1-1'
            },
            {
              id: 12,
              label: '二级 1-2'
            }
          ]
        }, 
        {
          id: 2,
          label: '一级 2',
          children: [
            {
              id: 21,
              label: '二级 2-1',
              children: [
                {
                  id: 211,
                  label: '三级 2-1-1'
                },
                {
                  id: 212,
                  label: '三级 2-1-2'
                }
              ]
            },
            {
              id: 22,
              label: '二级 2-2',
              children: [
                {
                  id: 221,
                  label: '三级 2-2-1'
                }
              ]
            }
          ]
        }
      ]
    }
  }
复制代码

4、 问题描述

问题一:

  • 点击配置opetation(scope.row.auth),需要弹出弹框并设置默认权限,这里我们通过id为依据来勾选,这是需要设置依据node-key="id"
    opetation (auth) {
      this.dialogVisible = true
      this.$refs.tree.setCheckedKeys(auth)
    }
复制代码

这时候将会报以下错误:

vue.esm.js?efeb:591 [Vue warn]: Error in event handler for "click": "TypeError: Cannot read property 'setCheckedKeys' of undefined"

相信很多人遇到过这个问题,这是因为this.dialogVisible = true时并没有立即更新dom,而是等整个逻辑执行完后再一次新渲染,因此此时的弹框并未渲染,在dom树中是不存在的,
this.$refs.tree is undefined的所以setCheckedKeys肯定也是undefined。

解决方法: this.$nextTick(),this.$nextTick()会在dom更新之后在执行回调:

opetation (auth) {
  this.dialogVisible = true
  this.$nextTick(function() {
    this.$refs.tree.setCheckedKeys(auth)
  })
}
复制代码

到这里每次打开弹框的时候都会获取最新的角色权限并勾选。

问题二:

  • 获取节点数据后,当父节点被勾选时,所有的子节点全部被勾选,而实际上很多时候只有部分子节点被勾选。
  1. 通过check的方法获取节点的信息:
      currentChecked(data, currentChecked) {
        const { checkedNodes, halfCheckedNodes } = currentChecked
        console.log(checkedNodes, halfCheckedNodes)
      }
    复制代码
  2. check的方法,有两个参数,该节点所对应的对象、树目前的选中状态对象(含checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性)。树节点的状态有三种,选中,部分选中,未选中。checkedNodes表示当前选中的节点,halfCheckedNodes表示部分选中(只可能存在于父节点,父节点下有部分子节点被选中)。
  3. 这里提供一个解决思路,记录选中节点的状态:
        currentChecked(data, currentChecked) {
          let auth = []
          const { checkedNodes, halfCheckedNodes } = currentChecked
          halfCheckedNodes.length && halfCheckedNodes.forEach(({ id }) => {
            auth.push({
              id,
              type: 2
            })
          })
          checkedNodes.length && checkedNodes.forEach(({ id }) => {
            auth.push({
              id,
              type: 1
            })
          })
          // api 将auth数据保存至后台
        }
    复制代码
  4. 修改opetation方法和listData数据,根据type过滤,只设置全部选中的节点(type=1),父节点会根据子节点的情况自动勾选。
    auth: [
        {
            id: 1,
            type:1
        }
    ]
    复制代码
    opetation (auth) {
      this.dialogVisible = true
      const arr = []
      auth.length &&auth.map(({ id, type }) => {
        type === 1 && arr.push(id)
      })
      this.$nextTick(function() {
        this.$refs.tree.setCheckedKeys(arr)
      })
    }
    复制代码

问题三:

  • 当我们将el-tree封装成一个公用的组件的时候,比如叫auth-tree,这是在页面中引用封装好的组件。
 <auth-tree
      ref="authTree"
      :show-checkbox="true"
      :tree-data="tableTreeData"
      @currentChecked="currentChecked"/>
复制代码

这时如果我们使用this.$refs.authTree.setCheckedKeys(auth) 仍然会报错:

vue.esm.js?efeb:591 [Vue warn]: Error in event handler for "click": "TypeError: Cannot read property 'setCheckedKeys' of undefined"
复制代码

解决办法:在父组件中:

click() {
    this.$refs.authTree.setCheckedKeys(auth) 
}
复制代码

在组件中添加setCheckedKeys方法:

setCheckedKeys(auth) {
    this.$refs.tree.setCheckedKeys(auth) 
}
复制代码

5、 总结

  • node-key="id", 设置节点状态的依据。
  • this.$nextTick()弹框打开后的回调。
  • setCheckedKeys()必须是通过节点本身的ref来直接。
  • checkedNodes, halfCheckedNodes,记录几点的不同状态。
  • 本文只是针对特定的场景的讲解,如遇到其它场景问题,欢迎留言一起讨论解决方案。
关注下面的标签,发现更多相似文章
评论