Element控件Tree實現(xiàn)數(shù)據(jù)樹形結(jié)構(gòu)的示例代碼
在前端開發(fā)中,有時會遇到所有菜單數(shù)據(jù)在同一級的情況,后端未對數(shù)據(jù)進行分級處理;但前端渲染需要是樹狀結(jié)構(gòu)的數(shù)據(jù),如何實現(xiàn)數(shù)據(jù)的樹狀化?將數(shù)組中通過父節(jié)點的ID與子節(jié)點的parentId關(guān)聯(lián),通過遞歸函數(shù)來實現(xiàn)。
前端框架這里使用element-ui的tree控件來實現(xiàn),對其不了解可以去官網(wǎng)查看文檔。
地址:Element - The world's most popular Vue UI framework
一、創(chuàng)建頁面
這里就不講vue項目的搭建了,基礎(chǔ)不好的,可以去官網(wǎng)查看文檔。
首先在src/pages目錄中,創(chuàng)建element-trees文件夾,再創(chuàng)建index.vue,代碼如下:
<template>
<div class="tree-container">
</div>
</template>
<script>
export default {
data(){
return {}
},
created() {},
methods: {}
}
</script>
<style lang="scss">
</style>在類選擇器tree-container容器中,添加相關(guān)按鈕和Tree控件,以及給容器添加些樣式進行修飾一下,代碼如下:
<template>
<div class="tree-container">
<div class="top-box">
<el-button type="primary" size="mini" @click="appendNode">添加菜單</el-button>
<el-button type="info" size="mini" @click="removeSelected">刪除選中項</el-button>
</div>
<el-tree
ref="tree"
:data="treeData"
:props="props"
accordion
show-checkbox
node-key="id"
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)">添加</el-button>
<el-button type="text" size="mini" @click="editor(data)">修改</el-button>
<el-button type="text" size="mini" @click="remove(node, data)">刪除</el-button>
</span>
</span>
</el-tree>
</div>
</template>
<script>
export default {
data(){
return {
props: {
label: 'name',
children: 'children'
},
treeData: []
}
},
created() {},
methods: {
//添加父節(jié)點數(shù)據(jù)
appendNode(){},
//添加子項數(shù)據(jù)
append(data){},
//編輯數(shù)據(jù)
editor(data){},
//移出項目
remove(node, data){},
//刪除選中的節(jié)點
removeSelected(){}
}
}
</script>
<style lang="scss">
.tree-container{ width: 360px; font-size: 12px;
.top-box{ text-align: right; padding-bottom: 20px; }
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>此時頁面效果如下:

二、模擬數(shù)據(jù)
在element-trees文件夾中添加data.js文件,用來存儲模擬數(shù)據(jù)。代碼如下:
/**
* 模擬數(shù)據(jù)
*/
const dataList = [
{
"name": "網(wǎng)絡(luò)安全滲透工程師體系大綱",
"pid": 0,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 1
},
{
"name": "WEB通信、前后端原理",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 2
},
{
"name": "信息收集",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 3
},
{
"name": "注入全方位利用+數(shù)據(jù)庫注入",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 4
},
{
"name": "前端滲透、文件上傳解析漏洞",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 5
},
{
"name": "漏洞利用",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 6
},
{
"name": "漏洞挖掘",
"pid": 1,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 7
},
{
"name": "Web服務(wù)器通信原理",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 8
},
{
"name": "后端基礎(chǔ)SQL",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 9
},
{
"name": "數(shù)據(jù)庫簡介及SQL語法",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 10
},
{
"name": "后端基礎(chǔ)SQL高級查詢與子查詢",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 11
},
{
"name": "后端基礎(chǔ)PHP簡介及基本函數(shù)上",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 12
},
{
"name": "后端基礎(chǔ)PHP—表單驗證",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 13
},
{
"name": "正則表達式",
"pid": 2,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 14
},
{
"name": "信息搜集的意義 — 滲透測試的靈魂",
"pid": 3,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 15
},
{
"name": "信息收集(一)",
"pid": 3,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 16
},
{
"name": "網(wǎng)絡(luò)架構(gòu)-信息收集",
"pid": 3,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 17
},
{
"name": "前端-信息收集",
"pid": 3,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 18
},
{
"name": "系統(tǒng)-信息收集",
"pid": 3,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 19
},
{
"name": "SQL注入的原理",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 20
},
{
"name": "滲透測試常用工具講解",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 21
},
{
"name": "POST注入/HEAD注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 22
},
{
"name": "盲注",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 23
},
{
"name": "XSS的原理分析與解剖",
"pid": 5,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 24
},
{
"name": "存儲型XSS",
"pid": 5,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 25
},
{
"name": " Dom Based XSS",
"pid": 5,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 26
},
{
"name": "XXE實體注入",
"pid": 6,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 27
},
{
"name": "SSRF-服務(wù)器端請求偽造",
"pid": 6,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 28
},
{
"name": "驗證碼繞過、密碼找回漏洞",
"pid": 7,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 29
},
{
"name": "平行越權(quán)、垂直越權(quán)",
"pid": 7,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 30
},
{
"name": "支付漏洞",
"pid": 7,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 31
},
{
"name": "Sql注入",
"pid": 7,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 32
},
{
"name": "變量覆蓋漏洞",
"pid": 6,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 33
},
{
"name": "本地包含與遠程包含",
"pid": 6,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 34
},
{
"name": "unserialize反序列化漏洞",
"pid": 6,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 35
},
{
"name": "CSRF",
"pid": 5,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 36
},
{
"name": "文件上傳解析漏洞",
"pid": 5,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 37
},
{
"name": "寬字節(jié)注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 38
},
{
"name": "Accsess注入 — Cookie注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 39
},
{
"name": "Accsess注入 — 偏移注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 40
},
{
"name": "MySQL注入 — Dns 注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 41
},
{
"name": "MSSQL注入 — 反彈注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 42
},
{
"name": "Oracle注入 — 報錯注入",
"pid": 4,
"createtime": "2023-03-29",
"updatetime": "2023-03-29",
"id": 43
}
];
export default dataList;文件創(chuàng)建好后,我們將其引入到index.vue文件中,代碼如下:
<script>
import DataList from './data'
export default {
data(){
return {
props: {
label: 'name',
children: 'children'
},
treeData: []
}
},
created() {
this.loadNode();
},
methods: {
//加載節(jié)點數(shù)據(jù)
loadNode(){
this.treeData = DataList.map(item => item);
},
//略...
}
}
</script>如上代碼,通過loadNode()函數(shù)執(zhí)行后,模擬數(shù)據(jù)則已與Tree控件進行了雙方綁定。但是頁面中顯示的數(shù)據(jù),全都顯示在同級位置。數(shù)據(jù)的歸類分級,我們在后面再講解。頁面效果如下:

三、遞歸函數(shù)
此時離成功緊一步之遙了,我們先來分析下data.js中的數(shù)據(jù)結(jié)構(gòu)。如下圖:

如何將數(shù)據(jù)歸類分級呢,可以通過循環(huán)判斷,每級的id與數(shù)據(jù)中的pid進行關(guān)聯(lián);比如第一條數(shù)據(jù)id為1,將數(shù)組進行遍歷查詢判斷pid有為1的數(shù)據(jù),則表示其有子項數(shù)據(jù),將其子項數(shù)據(jù)添加到children數(shù)組中。pid為0的為一級數(shù)據(jù),所以當(dāng)定義遞歸函數(shù)時,傳入的pid默認為0。
這里層次有可能是1層,2層,3層...... n層,要一層一層循環(huán)判斷,就太麻煩了;所以這里我們要使用遞歸方法,來實現(xiàn)n層級的數(shù)據(jù)處理。
在src下創(chuàng)建utils/utils.js文件,在utils.js中定義遞歸函數(shù),代碼如下:
/**
* 遞歸函數(shù)
* @param arr 數(shù)組
* @param pid 父ID,不傳默認為0
*/
export const DGFilterTrees = (arr, pid = 0) => {
let newArr = [];
//循環(huán)數(shù)組
arr.forEach((item, i) => {
//判斷pid與遍歷元素中pid相同的數(shù)據(jù),相等的為同級數(shù)據(jù),追加到該級數(shù)組中
if(item.pid == pid){
newArr.push(item);
/**
* 判斷該item元素是否有子項
* 當(dāng)數(shù)組中有元素的pid與item.id相等,some函數(shù)會返回true,表示該元素有子項數(shù)據(jù)
*/
if(arr.some(ele => ele.pid == item.id)){
//此時,通過重新調(diào)用本函數(shù)進行遞歸處理
item['children'] = DGFilterTrees(arr, item.id);
}
}
});
return newArr;
}注:遞歸算法是一種直接或者間接調(diào)用自身函數(shù)或者方法的算法。
遞歸算法的特點:
- 遞歸就是方法里調(diào)用自身。
- 在使用遞增歸策略時,必須有一個明確的遞歸結(jié)束條件,稱為遞歸出口。
- 遞歸算法解題通常顯得很簡潔,但遞歸算法解題的運行效率較低。所以一般不提倡用遞歸算法設(shè)計程序。
- 在遞歸調(diào)用的過程當(dāng)中系統(tǒng)為每一層的返回點、局部量等開辟了棧來存儲。遞歸次數(shù)過多容易造成棧溢出等,所以一般不提倡用遞歸算法設(shè)計程序。
所以在使用遞歸算法時,一定要注意判斷條件能正常退出,否則無法靠自身的控制終止的循環(huán),會導(dǎo)致棧溢出,程序卡死等問題。
將DGFilterTrees()遞歸函數(shù)引入到index.vue中,將模擬數(shù)據(jù)重組,代碼如下:
<script>
import DataList from './data'
import DGFilterTrees from '@/utils/utils.js'
export default {
data(){
return {
props: {
label: 'name',
children: 'children'
},
treeData: []
}
},
created() {
this.loadNode();
},
methods: {
//加載節(jié)點數(shù)據(jù)
loadNode(){
this.treeData = DGFilterTrees(DataList);
},
//略...
}
}
</script>此時,所有數(shù)據(jù)都進行了歸類分級顯示,頁面的效果圖如下:

四、選中后顯示按鈕
如上圖,我們會發(fā)現(xiàn)每項后面的添加、修改、刪除全顯示出來,會顯示擁擠并不方便操作。這里我們將節(jié)點輸出后會發(fā)現(xiàn),可以使用isCurrent來判斷,只顯示選中當(dāng)前項的按鈕。

在span標簽上添加v-if,判斷node.isCurrent是否為true,代碼如下:
<el-tree
ref="tree"
:data="treeData"
:props="props"
accordion
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span v-if="node.isCurrent">
<el-button type="text" size="mini" @click="append(data)">添加</el-button>
<el-button type="text" size="mini" @click="editor(data)">修改</el-button>
<el-button type="text" size="mini" @click="remove(node, data)">刪除</el-button>
</span>
</span>
</el-tree>如下圖,點擊選擇”后端基礎(chǔ)SQL“后,會顯示后面的操作按鈕。

五、刪除元素
這里我們是使用本地定義模擬數(shù)據(jù)進行操作的,所以沒有真實項目中是通過接口進行數(shù)據(jù)的增刪改查部分。代碼如下:
//移出項目
remove(node, data){
if(Array.isArray(data['children'])&&data.children.length>0){
this.$message.error('當(dāng)前數(shù)據(jù)有子項,無法刪除~');
return;
}
//查詢數(shù)據(jù)位置索引
let index = DataList.findIndex(item => item.id==data.id);
//刪除指定位置數(shù)據(jù)
DataList.splice(index, 1);
//重新加載數(shù)據(jù)
this.loadNode();
}效果如下圖:

六、刪除多選項
這里需要使用Tree控件的getCheckedNodes()函數(shù),來獲取被選中項;然后通過循環(huán),刪除每條被選中元素,代碼如下:
//移出項目
remove(node, data){
if(Array.isArray(data['children'])&&data.children.length>0){
this.$message.error('當(dāng)前數(shù)據(jù)有子項,無法刪除~');
return;
}
//查詢數(shù)據(jù)位置索引
let index = DataList.findIndex(item => item.id==data.id);
//刪除指定位置數(shù)據(jù)
DataList.splice(index, 1);
//重新加載數(shù)據(jù)
this.loadNode();
}效果如下圖:

本期就先介紹到這,添加、修改等功能也比較簡單,可以通過element-ui的$prompt彈框控件來實現(xiàn)。
到此這篇關(guān)于Element控件Tree實現(xiàn)數(shù)據(jù)樹形結(jié)構(gòu)的示例代碼的文章就介紹到這了,更多相關(guān)Element Tree樹形結(jié)構(gòu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 解決elementUI中el-tree樹形結(jié)構(gòu)中節(jié)點過濾的問題
- Element樹形控件el-tree懶加載并設(shè)置默認展開和選中的效果
- ElementUI 的 Tree 組件的基本使用實戰(zhàn)教程
- ElementUI中Tree組件使用案例講解
- elementUI如何動態(tài)給el-tree添加子節(jié)點數(shù)據(jù)children詳解
- element UI 中的 el-tree 實現(xiàn) checkbox 單選框及 bus 傳遞參數(shù)功能
- vue2+elementUI的el-tree的懶加載功能
- vue2+elementUI的el-tree的選中、高亮、定位功能的實現(xiàn)
- vue+elementUI組件tree如何實現(xiàn)單選加條件禁用
- element?el-tree折疊收縮的實現(xiàn)示例
相關(guān)文章
element-plus的自動導(dǎo)入和按需導(dǎo)入方式詳解
之前使用 ElementPlus 做項目的時候,由于不會使用按需引入耽誤了不少時間,這篇文章主要給大家介紹了關(guān)于element-plus自動導(dǎo)入和按需導(dǎo)入的相關(guān)資料,需要的朋友可以參考下2022-08-08
Vue電商網(wǎng)站首頁內(nèi)容吸頂功能實現(xiàn)過程
電商網(wǎng)站的首頁內(nèi)容會比較多,頁面比較長,為了能讓用戶在滾動瀏覽內(nèi)容的過程中都能夠快速的切換到其它分類。需要分類導(dǎo)航一直可見,所以需要一個吸頂導(dǎo)航的效果。目標:完成頭部組件吸頂效果的實現(xiàn)2023-04-04
Vue3中的defineExpose函數(shù)用法深入解析
這篇文章主要介紹了Vue3中的defineExpose函數(shù)用法的相關(guān)資料,defineExpose是Vue3中用于在模式下暴露組件內(nèi)部屬性和方法的輔助函數(shù),它允許父組件通過ref訪問子組件的暴露內(nèi)容,提高組件間的交互能力并保持封裝性,需要的朋友可以參考下2025-01-01

