為了方便, 本文所有的Angular
均表示Angula2及以上版本,對於使用Angular1
/Angular.js
的讀者可作為參考
前言
目前正在寫一個Angular
的Markdown
編輯器,需要一個樹形元件來寫檔案系統。剛好之前用過Angular Material
的樹形元件,就想照著寫一個。畢竟直接把Angular Material
引進來會多出其他用不到的元件,而且自己實現還能更深入學習Angular
。
介紹
在寫之前我百度了一通,發現大部分文章的Tree元件實現都是把節點模板直接寫在了元件裡,類似下面
<!--Tree元件-->
<tree>
<tree-node></tree-node>
</tree>
<!--TreeNode元件-->
<tree-node>
<!--本節點內容-->
{{ nodeName }}
<!--子節點-->
<tree-node *ngIf="hasChildren">
</tree-node>
<tree-node>
複製程式碼
說明一下: Tree
元件裡面包含TreeNode
元件,TreeNode
元件內部實現了遞迴子節點的邏輯。
其實這樣的結構已經足夠滿足我的需求了,但是(因為強迫症)這樣的可重用性幾乎是沒有,因為節點的內容已經寫死在TreeNode
元件裡了。
然後我想到了Angular Material
的CdkTree
。他的結構如下
<tree dataSource="ds">
<tree-node>
<!--本節點內容-->
{{ nodeName }}
<!--子節點出口-->
<outlet></outlet>
</tree-node>
</tree>
複製程式碼
說明: 簡單的說就是CdkTree
把<tree-node>
裡的內容作為一個模板儲存起來,然後根據資料來源遞迴渲染出來。這樣我們就可以在不修改Tree
和TreeNode
元件前提下改變其內容。
實現
在實現之前需要理解Angular
的幾個裝飾器,學過Angular
的應該都不會陌生。
@ViewChild
- 在檢視中查詢匹配的第一個元素@ViewChildren
- 在檢視中查詢匹配的所有元素@ContentChild
- 在元件標籤包裹的內容中查詢匹配的第一個元素@ContentChildren
- 在元件標籤包裹的內容中查詢匹配的所有元素
View和Content的區別
View: 在元件的模板中定義的內容,即我們手動寫在xxx.component.html裡的內容
Content: 在Host
元素的<opening>
和<closeing>
標籤中的內容
概覽
在Tree元件中有四個比較重要的類
@Component: TreeComponent
@Component: TreeNodeComponent
@Directive: TreeNodeOutletDirective
@Directive: TreeNodeDefDirective
TreeComponent
該元件就是我們要是實現的Tree
元件,用於包裹TreeNode
TreeNodeComponent
樹節點元件,我們自定義的模板就寫在這裡面
TreeNodeOutletDirective
這個指令設定了子節點的出口位置
TreeNodeDefDirective
這個指令用來定義樹節點所需的資料,即我們使用這個指令讓模板可以使用每個樹節點對應的資料
實現
我們先看一下完成後的樣子
<nb-tree [dataSource]="fileTree">
<nb-tree-node *nbTreeNodeDef="let data = data">
<li>
<span>{{ data.title }}</span>
</li>
<ul>
<ng-container nbTreeNodeOutlet></ng-container>
</ul>
</nb-tree-node>
</nb-tree>
複製程式碼
(標籤前面的nb請忽略,這只是預設的字首)上面是完成後的簡易版。
我們可以看到在tree
元件上設定了dataSource
。
然後在treeNodeDef
指令中我們匯出了資料物件data
。然後在模板中使用了它<span>{{ data.title }}</span>
。
最後我們在<ng-container>
上用treeNodeOutlet
指令設定了子節點的出口。
懶得詳細寫實習了。。。有空再寫吧。本文主要提供一個通用樹形元件的思路。
想看程式碼的,看結尾。有一個不是很完善的tree
元件,我用在正在寫的Markdown編輯器上了。
結尾
Github: tree
元件連結