共计 2315 个字符,预计需要花费 6 分钟才能阅读完成。
问题形容
本文波及到的代码地位:https://github.com/wangzixi-d…
看这样一组 parent Component 和 child Component:
@Component({ | |
selector: 'child', | |
template: `<span>I am a child.</span>` | |
}) | |
export class ChildViewComponent {} | |
@Component({ | |
selector: 'parent', | |
template: ` | |
<div> | |
projected content: | |
<ng-content></ng-content> | |
</div> | |
` | |
}) | |
export class ParentComponent {} | |
@Component({ | |
selector: 'demo', | |
template: ` | |
<parent id="p1"> | |
<child id="c1"></child> | |
</parent> | |
<child id="c2"></child> | |
` | |
}) | |
export class Demo {} |
其中 parent Component 定义了一个内容投影区域,通过下列高亮代码,将子 Component 的内容投射进来:
即该区域:
最初的运行时成果:
问题剖析
当上述利用被 load 但尚未实现 bootstrap
时,Ivy 将其解析为如下的 TView
:
const tChildComponentView = new TView( | |
tData: [new TElementNode(‘span’), | |
new TTextNode(‘I am a child.’), | |
], | |
…, | |
); | |
const tParentComponentView = new TView( | |
tData: [new TElementNode(‘div’), | |
new TTextNode(‘projected content:‘), | |
new TProjectionNode(),], | |
…, | |
); | |
const tDemoAppView = new TView( | |
tData: [new TElementNode(‘parent’, [‘id’,‘p1’]), | |
new TElementNode(‘child’, [‘id’,‘c1’]), | |
new TElementNode(‘child’, [‘id’,‘c2’]), | |
], | |
…, | |
) |
接下来的步骤就是 bootstrap
,具体的逻辑就是基于 TView
创立 LView
:
const lParentComponentView_p1 = new LView( | |
tParentComponentView, | |
new ParentComponent(…), | |
document.createElement(‘div’), | |
document.createText(‘projected content:‘), | |
); | |
const lChildComponentView_c1 = new LView( | |
tChildComponentView, | |
new ChildComponent(…), | |
document.createElement(‘span’), | |
document.createText(‘I am a child.’), | |
); | |
const lChildComponentView_c2 = new LView( | |
tChildComponentView, | |
new ChildComponent(…), | |
document.createElement(‘span’), | |
document.createText(‘I am a child.’), | |
); | |
const lDemoAppView = new LView( | |
tDemoAppView, | |
new DemoApp(…), | |
document.createElement(‘parent’), | |
lParentComponentView_p1, | |
document.createElement(‘child’), | |
lChildComponentView_c1, | |
document.createElement(‘child’), | |
lChildComponentView_c2, | |
) |
上述逻辑在调试器里如下图所示:
其中 JerryAppComponent
被保护为 bootstrap
Component:
上述代码展现了 TView
和 LView
二者的区别。
再看 ChildComponent,TView 的实例只有一个,而 LView 的实例却有两个,因为 ChildComponent 被应用了两次。另一个要害区别是 LView 只存储 特定于该组件实例
的数据——例如 组件实例和关联的 DOM 节点
。TView 存储在组件的所有实例之间共享的信息——例如 须要创立哪些 DOM 节点
。
在下面的示例中,LView 显示为一个类(new LView(…)。实际上,咱们将它存储为一个数组([…])。将 LView 存储为一个数组是出于内存性能的起因。每个模板都有不同数量的 DOM 节点和子组件 / 指令,将其存储在数组中是最无效的形式。
应用数组进行存储的含意是不分明在数组中的哪个地位存储实例数据。TData 用于形容 LView 中每个地位存储的内容。所以 LView 自身不足以推理,因为它在没有上下文的状况下存储值。TView 形容了组件须要什么,但它不存储实例信息。通过将 LView 和 TView 放在一起,Ivy 能够拜访和推理 LView 中的值。LView 存储值,而 TView 存储 LView 中值的含意,相似 元数据
或者 schema
的概念。
为简略起见,LView 仅存储 DOM 节点。在实践中,LView 还存储绑定、注入器、净化器以及与视图状态相干的任何其余内容(在 TView/TData 中具备相应的条目。)
总结
思考 View 和 View 的一种办法是将这些概念与面向对象的编程分割起来。TView 就像类,而 View 就像类实例。