vue目錄樹組件

I would like to commemorate last year and today, my life is full of regret.

通常數據類展現內容,大多采用樹狀結構展現內容。相似效果以下:
javascript

左側是導航分類,能夠進行新建,對單項導航分享和刪除。單擊導航,在右側查詢出當前導航下全部目錄結構,能夠新建目錄。新增類型分爲三種,目錄能夠無限嵌套,固然也能夠設置層級。css

頁面總體佈局
頁面分爲左右兩個部分。左側列表,經過路由跳轉顯示右側內容。左側列表分爲上下兩塊,頂部是添加按鈕,下面是導航列表。

less樣式。
@import "../../theme/variables.less";
.main { position: relative; height: 100%;    overflow: hidden; .content { border: 1px solid #dcdcdc; position: relative; height: 100%; background: #f1f2f7; display: flex;        border-radius: @borderRadius; .left { width: 240px; background: #fff; border-right: 1px solid rgba(220, 220, 220, 1); padding: 15px 10px; display: flex; flex-direction: column;            overflow: auto; .header { width: 100%; margin-bottom: 20px; display: flex; justify-content: center;                align-items: center; .btn { width: 136px;                    margin: 0 6px; :global { .icon { margin-right: 14px;                        } .customIcon { display: inline-block; transform: rotate(45deg); } } }            } .treeLayout {                flex: 1; .item { width: 100%; height: 32px; line-height: 32px; margin-bottom: 11px;                    position: relative; .link { display: flex; align-items: center; font-size: 14px; font-family: Microsoft YaHei; font-weight: 400; color: rgba(51, 51, 51, 1); padding-left: 21px;                        cursor: pointer; .catalogIcon { font-size: 12px;                        } .text { display: inline-block; flex: 1; margin-left: 12px;                        } .opBtn { width: 46px; display: flex; align-items: center; justify-content: space-between;                        } .operateIcon { display: none;                        } &:hover {                            color: #00a4ff; .opBtn { color: rgba(51, 51, 51, 1);                            } .operateIcon { display: block; } }                    } .iconBtns { position: absolute; top: 28px; right: 24px; width: 112px; background: rgba(255, 255, 255, 1); box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.13); border-radius: 4px;                        z-index: 10; .icon { width: 100%; height: 40px; border-radius: 2px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-family: Microsoft YaHei; font-weight: 400; color: rgba(51, 51, 51, 1);                            cursor: pointer; .iconName { margin-left: 18px;                            } &:hover { background: #e7e8e9; } }                    }                }                .itemActive { .link {                        color: #00a4ff; .opBtn { color: rgba(51, 51, 51, 1);                        } .operateIcon { display: block; } } } }        } .right { flex: 1; width: 100%; overflow: hidden; } }}

這裏的導航列表,新增導航,和刪除都是調用相關接口。
前端

目錄樹組件java

頁面右側就是樹狀結構列表,經過路由跳轉攜帶catalogId參數,接口查詢出列表數據,後端返回的數據就是有層級的樹狀結構。node

我認爲的寫一個組件,單指這裏的目錄樹組件,組件中只須要構造出頁面佈局,任何的交互邏輯都不涉及,只將相關事件拋出便可。這就須要先明確好數據結構,來寫樣式佈局了。
typescript

數據結構,有id,name,父級id,子節點數組,類型catalogType:1是目錄,2是場景,3是外鏈場景 ... 以下:後端

樹狀結構會涉及到遞歸,這裏爲了處理方便,組件中分爲兩層。組件目錄結構以下:
數組

index就是對外暴露的窗口,主要目錄樹的佈局樣式是在DomNode中。先明確一下佈局,目錄樹中單個一行,須要一個展開收起的圖標,當前行類型的圖標,這裏業務上分三種類型,就須要以此判斷顯示不一樣圖標。每項最後還會有四個操做按鈕。
ruby

這裏把事件簡化了,只分了兩個事件,一個是展開收起,一個是一系列編輯操做,傳個type參數做爲區分。
微信

tabNode(node: ITree) { this.$emit("tabNode", node);},
// 操做doNode(node: ITree, type: string, index: number) { this.$emit("doNode", node, type, index);},

index文件中引用DomNode,相關的接收的參數和拋出去的事件,和DomNode一致。

// index佈局<div class="treeLayout"> <DomNode v-for="(item, index) in trees" :key="index" :node="item" @tabNode="tabNode" @doNode="doNode" :index="index" ></DomNode></div>
// 接收的參數props: { trees: { type: Array as () => ITree[], default: [], }, activeId: { type: String, default: "", },},
頁面右側實現
引用catalogTree組件。
<catalog-tree :trees="treeList" @tabNode="tabNode" @doNode="doNode"></catalog-tree>
前文已經提過,目錄數據是後端返回的,那麼treeList就是後端返回值res.data。但操做tabNode和doNode這兩個方法,須要將treeList數組轉換成map對象。
由於須要自定義添加一些字段,這些字段只做爲前端交互操做邏輯使用,因此後端返回值中不會攜帶。
須要給每一項數據添加isOpen字段,用來判斷展開收起狀態。level字段,用來實現上移下移操做。
先來構造這個catalogMap,定義個方法setCatalogMap,須要的參數有存放結果的treeMap,原數據treeList數組。
setCatalogMap ,很簡單的一個遞歸。

拿到map對象,就能夠實現tabNode和doNode這兩個方法。
// 切換狀態tabNode(node: ITree) { if (node.isOpen) { this.treeMap[node.catalogId].isOpen = false; } else { this.treeMap[node.catalogId].isOpen = true; }},
// 編輯等一系列操做,按照類型區分doNode(node: ITree, type: string, index: number) { switch (type) { case "up": // 上移 this.doUp(node, index); break; case "down": // 下移 this.doDown(node, index); break; case "edit": // 編輯 this.doEdit(node.catalogId); break; case "delete": // 刪除 this.doDelete(node); break; }},
有認真看的話,會發現,並無在哪裏定義isOpen屬性,怎麼就在tabNode方法中使用了。
由於我尚未寫。
拿到map對象,循環作個判斷,用來保持isOpen狀態。
Object.keys(treeMap).forEach((key) => { const item = treeMap[key]; if (this.treeMap[key]) { item.isOpen = this.treeMap[key].isOpen; } else { item.isOpen = true;    }});
doNode中的四個方法,編輯和刪除就是調個接口,主要是上移下移操做,前端實現數據的排序,最後將最新的數據返回給後端保存,doSaveSort方法調接口保存。
上代碼,好好琢磨琢磨。
doUp(node: ICatalogModel, index: number) { if (index === 0) { return; } const parentId: string = node.catalogParent as string; const parentItem: ICatalogModel = this.treeMap[parentId];
let dataList: ICatalogModel[] = []; // 若是爲空則是頂級 if (parentItem) { if (parentItem.catalogTreeVoList) { dataList = parentItem.catalogTreeVoList; } } else { dataList = this.treeList; } const item = dataList[index]; dataList.splice(index, 1); dataList.splice(index - 1, 0, item); this.doSaveSort(dataList);},
doDown(node: ICatalogModel, index: number) { const parentId: string = node.catalogParent as string; const parentItem: ICatalogModel = this.treeMap[parentId]; // 若是爲空則是頂級 let dataList: ICatalogModel[] = []; if (parentItem) { if (parentItem.catalogTreeVoList) { // 最後一個不能下移 if (parentItem.catalogTreeVoList.length === (index + 1)) { return; } else { dataList = parentItem.catalogTreeVoList; } } } else { // 一級最後一個不能下移 if ( this.treeList.length === (index + 1)) { return; } dataList = this.treeList; } const item = dataList[index]; dataList.splice(index, 1); dataList.splice(index + 1, 0, item); this.doSaveSort(dataList);},
總結
樹狀結構列表,首先須要明確數據結構,必備的字段id,name,父級id,children數組,根據數據結構,使用遞歸構建佈局。

over~加班快樂

本文分享自微信公衆號 - 前端一塊兒學(gh_3ba18d51f982)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索