使用過程描述:文件目錄樹的操作要求是,樹的結構數據不能一次性吐出,點擊樹的節點,加載該節點下的數據,除了數據加載的情況外,還有相關子節點的新建。當時沒有看elementUI關於el-tree組件的詳細文檔,就是感覺文件數在數據子節點的遞歸上會有麻煩;所以試過幾個方法,嘗試過自己寫組件,利用遞歸的方法一次性將文件數加載出來,最後勉強能夠加載,但是新增子節點這塊又遇到麻煩,就是還要根據遞歸將新增的子節點加載到選中的節點下,還是用遞歸,整個過程寫下來很痛苦,使用的體驗也不是很完美。最後又倒騰到el-tree上,回到官網老老實實滴看了各種函數使用說明。歸結起來找到el-tree的擴展方法:新增子節點和刪除子節點。
<el-tree
:data="data"
show-checkbox
node-key="id"
ref="tree"
default-expand-all
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button
type="text"
size="mini"
@click="() => append(data)">
Append
</el-button>
<el-button
type="text"
size="mini"
@click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
append(data) {
const newChild = { id: id++, label: 'testtest', children: [] };
if (!data.children) {
this.$set(data, 'children', []);
}
data.children.push(newChild);
},
remove(node, data) {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id === data.id);
children.splice(index, 1);
}
通過嘗試,的確可以滿足大部分的使用需求,但是依然存在問題。新增節點靜態數據插入到目標節點上是沒問題,但是實際情況是需要先查詢當前目標節點的children的數據,然後將新增的data數據push到children,最後將children利用$set方法改變目標節點。實際操作中邏輯沒有問題,但就是不成功,通過控制檯打印出來的結果也是新增了一條的數據children,可是文件樹卻不能更新。使用了官網提供的updateKeyChildren(通過 keys 設置節點子元素,使用此方法必須設置 node-key 屬性)也沒有用。後來通過控制檯打印觀察,發現每次操作更新節點數據之前children數據已經被更新,但是感覺就是有一個點沒有抓住,網上查找了很多資料,找到一個關於date數據深拷貝的說法,感覺很有道理,就試了試,沒想到竟然真的成功了。一個問題困擾了自己好多天,終於被解決的感覺真是太美妙了。
完整代碼如下,供下次參考。
<el-tree ref="tree" :data="dataTree"
:props="defaultProps"
node-key="id"
:default-expand-all="true" // 目錄樹默認是否全部展開
:highlight-current="true" // 選中節點是否高亮(加背景色區分)
:expand-on-click-node="false"
@node-click="handleNodeClick">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span v-if="!data.isedit">
<i class="el-icon-folder"></i>
{{ node.label }}</span>
<span v-else>
<el-input v-model="data.dirName" size="mini" @keyup.enter.native="saveDir(data)">
<!-- <template slot="append" style="padding: 0 10px;">
<i class="el-icon-check" @click.stop="saveDir(data)"></i></template> -->
</el-input>
</span>
<span style="font-size:20px;">
<el-button type="text" size="mini" @click.stop="() => append(data,node)">
<i class="el-icon-plus"></i>
</el-button>
<el-button type="text" size="mini" v-if="node.level !== 1"
@click="() => editDir(node,data)">
<i class="el-icon-edit"></i>
</el-button>
<el-button type="text" size="mini" v-if="node.level !== 1" @click="() => remove(node, data)">
<i class="el-icon-delete"></i>
</el-button>
</span>
</span>
</el-tree>
// JS部分
// 這步的操作是解決問題的關鍵
// let dataObj = JSON.parse(JSON.stringify(data)) // 深度拷貝
async append (data,node) {
// 這步的操作是解決問題的關鍵
let dataObj = JSON.parse(JSON.stringify(data)) // 深度拷貝
// 先查詢當前文件夾是否有子目錄
if (dataObj.children.length === 0) {
let result = await this.$axios.getMyDirectoryList({directorypath: dataObj.dirPath})
let res = this.$formatdata(result)
if (res.code === 10000 && res.data.length > 0) {
res.data.forEach(item=>{
item.isedit=false;
item.isUpdate=false;
item.children=[]
dataObj.children.push(item)
})
this.setNewFolder(dataObj, node)
} else {
this.setNewFolder(dataObj, node)
}
} else {
this.setNewFolder(dataObj, node)
}
},
setNewFolder (data,node) {
let dataChild = data.children
let dirName = '新建文件夾'
if (dataChild) {
let count=1
dataChild.forEach(item => {
if (item.dirName.indexOf('新建文件夾')>-1) {
count++
}
})
dirName += count
}
// 新增節點對象
const newChild = {
id: data.dirPath+'/'+dirName,
dirName,
dirPath:data.dirPath+'/'+dirName,
parentId: data.dirPath,
isedit: true,
isUpdate: false,
children: []
}
if (!data.children) {
this.$set(data, 'children', []);
}
dataChild.push(newChild);
this.$nextTick(() => {
// this.$set(data, 'children', data.children);
this.$refs['tree'].updateKeyChildren(data.id,dataChild)
})
},
this.$refs['tree'].updateKeyChildren(data.id,dataChild)
// 這個方法可以脫離函數對象流操作文件樹,只要知道目標對象,以及新增之後的對象數組即可使用此方法更新el-tree對象
// 使用注意點:通過 keys 設置節點子元素,使用此方法必須設置 node-key 屬性
記錄下這段文字希望爲遇到同樣問題的童鞋們提供點參考,記得深拷貝試試,哈哈!!!
el-tree 官網擴展:
props
參數 |
說明 |
類型 |
可選值 |
默認值 |
label |
指定節點標籤爲節點對象的某個屬性值 |
string, function(data, node) |
— |
— |
children |
指定子樹爲節點對象的某個屬性值 |
string |
— |
— |
disabled |
指定節點選擇框是否禁用爲節點對象的某個屬性值 |
boolean, function(data, node) |
— |
— |
isLeaf |
指定節點是否爲葉子節點,僅在指定了 lazy 屬性的情況下生效 |
boolean, function(data, node) |
— |
— |
//props的使用舉例
<template>
<el-tree :data="data" :props="defaultProps"></el-tree>
</template>
<script>
export default{
data () {
return {
data: [
{title:'一級目錄', list: [
{
title: '二級目錄',
list: [...]
}
]}
],
defaultProps:{
label: 'title', // label代替data裏面的title顯示在目錄樹上
children: 'list' // children代替data裏面的list顯示子節點目錄樹
}
}
}
}
</script>