使用NG
初始化一個簡單的Hello World!
的Sample
。javascript
渲染完成後的DOM
以下所示:html
<app-root _nghost-ifx-c0="" ng-version="8.2.14"> <app-hello-world _ngcontent-ifx-c0="" _nghost-ifx-c1=""> <p _ngcontent-ifx-c1="">Hello World!</p> </app-hello-world> </app-root>
根據渲染結果代表,渲染後的DOM
中原組件節點<app-hello-world></app-hello-world>
被保留,用於包裹組件模板內容。java
固然這種設計是沒問題的,由於上級可能給組件加屬性,可是若是在某些狀況下會很難處理。git
<div class="page"> <app-subject-preview></app-subject-preview> </div>
仍是試題預覽的需求,循環遍歷試題,使用了試題預覽組件,試題預覽渲染後的DOM
是這樣的。github
<div class="page"> <app-subject-preview> <p>完型填空大題幹</p> <p>31. A.xx B.xx C.xx D.xx</p> <p>32. A.xx B.xx C.xx D.xx</p> <p>33. A.xx B.xx C.xx D.xx</p> <p>34. A.xx B.xx C.xx D.xx</p> </app-subject-preview> </div>
子節點獲取到的是一個個app-subject-preview
,因分頁時高度計算調用十分頻繁,不易處理較繁重的計算任務,若是遞歸向下獲取直到沒有子元素時再處理,恐會產生性能問題。算法
期待生成的DOM
以下,沒有組件調用的那一層,易於處理:app
<div class="page"> <p>完型填空大題幹</p> <p>31. A.xx B.xx C.xx D.xx</p> <p>32. A.xx B.xx C.xx D.xx</p> <p>33. A.xx B.xx C.xx D.xx</p> <p>34. A.xx B.xx C.xx D.xx</p> </div>
Github
上2017
年04
月25
日有人提出了該問題,但願和ng-container
同樣,認爲組件的標籤應該是可選的,可渲染成註釋,不該該強制顯示。至今官方未解決。框架
Components host-element should (optional) be a html-comment instead of html-element - Github性能
問題的討論中提出了幾個方案,使用ViewContainerRef
,經測試無效。測試
一位老哥發帖參考了React
,提出了Fragment
的方案,我的以爲該方案很是好,但官方遲遲未採納。
去看了一下隔壁Vue
的渲染方式(Vue
規範中不推薦用;
)。
掛載一個Vue
應用:
var app = new Vue({ el: '#app' })
建立一個Vue
組件:
Vue.component('helloWorld', { template: '<p>Hello World!</p>' })
HTML
頁面:
<body> <div id="app"> <hello-world></hello-world> </div> </body>
DOM
渲染結果:
<body> <div id="app"> <p>Hello World!</p> </div> </body>
這種渲染結果算是比較理想的,但組件必須存在一個根標籤也會形成額外的問題,強制組件有根標籤也會形成多一層的問題。
將組件的p
標籤去掉,會產生以下錯誤:
兩者在建立組件時都須要組件擁有根元素,Angular
是保留了原組件標籤做爲根元素,Vue
是強制組件聲明一個根標籤做爲根元素,二者實現相似。
我沒有閱讀過Angular
與Vue
的框架源碼,但從官方遲遲未解決該問題,且多款框架都採用相似方式實現來推測,應該與檢測算法有關,多個根元素可能不利於檢測算法的實現。
退而求其次,只能棄用組件的方式,手動經過ng-template/ng-container
實現。
這裏我推薦使用ng-container
來減小循環帶來的層級嵌套問題,使用方式與正常指令使用一致。
<ng-container *ngFor="let item of arr"> {{ item }} </ng-container> <div *ngFor="let item of arr"> {{ item }} </div>
DOM
渲染結果以下所示(全部的ng-container
都被渲染爲註釋):
<app-root _nghost-ohv-c0="" ng-version="8.2.14"> <!--bindings={ "ng-reflect-ng-for-of": "0,1,2,3,4,5,6,7,8,9" }--> <!----> 0 <!----> 1 <!----> 2 <!----> 3 <!----> 4 <!----> 5 <!----> 6 <!----> 7 <!----> 8 <!----> 9 <!--bindings={ "ng-reflect-ng-for-of": "0,1,2,3,4,5,6,7,8,9" }--> <div _ngcontent-ohv-c0="">0</div> <div _ngcontent-ohv-c0="">1</div> <div _ngcontent-ohv-c0="">2</div> <div _ngcontent-ohv-c0="">3</div> <div _ngcontent-ohv-c0="">4</div> <div _ngcontent-ohv-c0="">5</div> <div _ngcontent-ohv-c0="">6</div> <div _ngcontent-ohv-c0="">7</div> <div _ngcontent-ohv-c0="">8</div> <div _ngcontent-ohv-c0="">9</div> </app-root>
但願官方能夠關注這個問題,並及時解決。
本文做者: 河北工業大學夢雲智開發團隊 - 張喜碩