Angular Renderer (渲染器)的具体使用(5)
步骤一
当 Angular 在创建组件视图时,会根据 nodeDef.element 对象的 componentRendererType 属性值,来创建组件的渲染器。接下来我们先来看一下 NodeDef 、 ElementDef 和 RendererType2 接口定义:
// packages/core/src/view/types.ts
// 视图中节点的定义
export interface NodeDef {
bindingIndex: number;
bindings: BindingDef[];
bindingFlags: BindingFlags;
outputs: OutputDef[];
element: ElementDef|null; // nodeDef.element
provider: ProviderDef|null;
// ...
}
// 元素的定义
export interface ElementDef {
name: string|null;
attrs: [string, string, string][]|null;
template: ViewDefinition|null;
componentProvider: NodeDef|null;
// 设置组件渲染器的类型
componentRendererType: RendererType2|null; // nodeDef.element.componentRendererType
componentView: ViewDefinitionFactory|null;
handleEvent: ElementHandleEventFn|null;
// ...
}
// packages/core/src/render/api.ts
// RendererType2 接口定义
export interface RendererType2 {
id: string;
encapsulation: ViewEncapsulation; // Emulated、Native、None
styles: (string|any[])[];
data: {[kind: string]: any};
}
步骤二
获取 componentRendererType 的属性值后,如果该值为 null 的话,则直接使用 parentView.root 属性值对应的 renderer 对象。若该值不为空,则调用 parentView.root 对象的 rendererFactory() 方法创建 renderer 对象。
通过上面分析,我们发现不管走哪条分支,我们都需要使用 parentView.root 对象,然而该对象是什么特殊对象?我们发现 parentView 的数据类型是 ViewData ,该数据接口定义如下:
// packages/core/src/view/types.ts
export interface ViewData {
def: ViewDefinition;
root: RootData;
renderer: Renderer2;
nodes: {[key: number]: NodeData};
state: ViewState;
oldValues: any[];
disposables: DisposableFn[]|null;
// ...
}
通过 ViewData 的接口定义,我们终于发现了 parentView.root 的属性类型,即 RootData:
// packages/core/src/view/types.ts
export interface RootData {
injector: Injector;
ngModule: NgModuleRef<any>;
projectableNodes: any[][];
selectorOrNode: any;
renderer: Renderer2;
rendererFactory: RendererFactory2;
errorHandler: ErrorHandler;
sanitizer: Sanitizer;
}
那好,现在问题来了:
- 什么时候创建
RootData对象? - 怎么创建
RootData对象?
什么时候创建 RootData 对象?
当创建根视图的时候会创建 RootData,在开发环境会调用 debugCreateRootView()
