使用element-ui的el-tree元件入坑講解之setCheckedKeys

SilentLove發表於2018-12-03

1、前提基礎

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

2、業務場景描述

  1. 假設現在我們有一個人員列表,需要給每個人配置特定的許可權來限制哪些人可以幹些什麼:
    使用element-ui的el-tree元件入坑講解之setCheckedKeys
    使用element-ui的el-tree元件入坑講解之setCheckedKeys

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,記錄幾點的不同狀態。
  • 本文只是針對特定的場景的講解,如遇到其它場景問題,歡迎留言一起討論解決方案。

相關文章