通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念
问题描述
本文涉及到的代码位置:https://github.com/wangzixi-d...
看这样一组 parent Component 和 child Component:
@Component({
selector: 'child',
template: `I am a child.`
})
export class ChildViewComponent {}@Component({
selector: 'parent',
template: `projected content:
`
})
export class ParentComponent {}@Component({
selector: 'demo',
template: `
`
})
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:文章图片
【通过单步调试的方式学习|通过单步调试的方式学习 Angular 中 TView 和 LView 的概念】上述代码展示了
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 就像类实例。
推荐阅读
- 通过单步调试的方式学习|通过单步调试的方式学习 Angular 中带有选择器的内容投影使用方式
- 关于|关于 Angular view Query 的 id 选择器问题的单步调试
- Angular|Angular 内容投影出现 No provider for TemplateRef found 错误的单步调试
- Angular|Angular 内容投影 content projection 关于条件渲染问题的单步调试
- Angular|Angular 内容投影 content projection 关于选择器问题的单步调试
- Angular|Angular 基于自定义指令的内容投影 content projection 问题的单步调试
- 关于施加在|关于施加在 div 标签上的 ngTemplateOutlet 指令让 div class 丢失的问题调试
- 关于|关于 ng-template 通过 @input 传入另一个 Component 不能工作的问题调试
- 单片机|K210识别数字(0~9)并与单片机通信通过数字来控制小车移动
- OpenResty入门