1、前提基礎
- 掌握vue、element-ui相關前端知識,若有還沒掌握的童鞋可以先去看我的vue全家桶一文:juejin.im/post/5bfe4a…。
2、業務場景描述
- 假設現在我們有一個人員列表,需要給每個人配置特定的許可權來限制哪些人可以幹些什麼:
3、程式碼
- 新建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>
複製程式碼
- 模擬資料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)
})
}
複製程式碼
到這裡每次開啟彈框的時候都會獲取最新的角色許可權並勾選。
問題二:
- 獲取節點資料後,當父節點被勾選時,所有的子節點全部被勾選,而實際上很多時候只有部分子節點被勾選。
- 通過check的方法獲取節點的資訊:
currentChecked(data, currentChecked) { const { checkedNodes, halfCheckedNodes } = currentChecked console.log(checkedNodes, halfCheckedNodes) } 複製程式碼
- check的方法,有兩個引數,該節點所對應的物件、樹目前的選中狀態物件(含checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四個屬性)。樹節點的狀態有三種,選中,部分選中,未選中。checkedNodes表示當前選中的節點,halfCheckedNodes表示部分選中(只可能存在於父節點,父節點下有部分子節點被選中)。
- 這裡提供一個解決思路,記錄選中節點的狀態:
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資料儲存至後臺 } 複製程式碼
- 修改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,記錄幾點的不同狀態。
- 本文只是針對特定的場景的講解,如遇到其它場景問題,歡迎留言一起討論解決方案。