我看有不少人看到這個《Ant-design-vue 樹形控件tree 新增節點,刪除節點,編輯節點的解決方案》文章以後,有不少疑惑,關於刪除,增加的問題,以及key重複的問題,我發的這篇文章只是提供了一個思路。
整合下,還是對你們詳解一下,可能有些人看得不是很明白
關於dom
<a-button type="primary" @click="add">添加頂級菜單</a-button>
<a-tree
showLine
@expand="onExpand"
:expandedKeys="expandedKeys"
:autoExpandParent="autoExpandParent"
:treeData="treeData"
style="margin-top:20px"
>
<template slot="custom" slot-scope="item">
<span>{{ item.title }}</span>
<a-button size="small" class="but_type" style="right:220px;" @click="()=> stop(item)">{{ item.menuStatus===0?'啓用':'禁用' }}</a-button>
<a-button size="small" class="but_type" style="right:160px;" @click="()=> append(item)">新增</a-button>
<a-button
class="but_type"
size="small"
style="right:100px;"
@click="()=> handleEdit(item)"
>編輯</a-button>
<a-button class="but_type" size="small" @click="(e)=> remove(item)">刪除</a-button>
</template>
</a-tree>
在DOM中,關於樹的操作一共有4個事件,分別是
- 添加頂級菜單事件add,
- 啓用和禁用菜單事件stop,
- 新增菜單事件append,
- 刪除菜單事件remove
- 編輯菜單事件handleEdit
關於邏輯
- 首先我這邊後臺給的是一個一維數組,我需要把後臺給的數組轉換爲樹形結構,因此寫了個方法
function treeDataTranslate (data, id = 'pid', pid = 'parentId') {
var res = []
var temp = {}
for (var i = 0; i < data.length; i++) {
data[i]['key'] = data[i].pid
data[i]['title'] = data[i].menuName
temp[data[i][id]] = data[i]
data[i].scopedSlots = { title: 'custom' }
}
for (var k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]]['children']) {
temp[data[k][pid]]['children'] = []
}
if (!temp[data[k][pid]]['_level']) {
temp[data[k][pid]]['_level'] = 1
}
data[k]['_level'] = temp[data[k][pid]]._level + 1
temp[data[k][pid]]['children'].push(data[k])
} else {
res.push(data[k])
}
}
return res
}
通過這個方法轉換出來的數據就是我想要的數據結構即DOM中的treeData數據
- 其次當我需要修改和刪除菜單的時候我需要在treeData中找到我需要刪除和修改的項,因此也需要寫一個工具函數
//該函數接收4個參數,option爲我需要修改或者刪除的數據項,arr爲格式化後的treeData,type是需要操作的類型,默認爲delect,obj爲編輯後的數據,默認爲空對象
searchOption (option, arr, type = 'delect', obj = {}) {
//首先循環arr最外層數據
for (let s = 0; s < arr.length; s++) {
//如果匹配到了arr最外層中的我需要修改的數據
if (arr[s].key === option.key) {
//判斷需要操作的類型
if (type === 'delect') {
//刪除即刪除即可
arr.splice(s, 1)
} else {
//如果是修改,利用Object.assign()組合符合arr數據格式的對象,並進行修改
this.$set(
arr,
s,
Object.assign(obj, {
key: obj.pid,
title: obj.menuName,
children: option.children,
scopedSlots: { title: 'custom' }
})
)
}
break
} else if (arr[s].children && arr[s].children.length > 0) {
// 遞歸條件
this.searchOption(option, arr[s].children, type, obj)
} else {
continue
}
}
},
- 關於增加菜單就不用說了,找到父級id,將增加的數據傳給後臺,成功後重新獲取tree數據就行
- 編輯菜單
handleEdit(data){
//data爲原數據,this.addParamData爲修改後的數據
//this.addParamData爲傳給後臺接口的參數,具體依據項目而定
saveSysMenu(this.addParamData)
.then(result => {
if (result) {
this.scopeVisible = false
this.noticeMessage('操作成功')
//編輯成功以後後臺會把編輯成功後的菜單數據返回回來,然後調用this.searchOption()方法即可
this.scopeTitle === '編輯菜單'
? this.searchOption(this.addData, this.treeData, 'edit', result.result)
: this.getMenuList()
}
})
.catch(err => {
console.log(err)
})
}
- 刪除菜單
remove(data){
deleteMenu({ pid: data.pid })
.then(result => {
if (result) {
this.visible = false
//刪除成功後調用this.searchOption()的刪除方法即可
this.searchOption(this.addData, this.treeData)
}
})
.catch(err => {
console.log(err)
})
.finally(() => {
this.confirmLoading = false
})
}
此案例只是提供一種思路,主要是借鑑爲主