使用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>
但愿官方能够关注这个问题,并及时解决。
本文做者: 河北工业大学梦云智开发团队 - 张喜硕