vue项目接口域名动态的获取方法
693
2023-05-13
详解Angular 4.x NgIf 的用法
NgIf 指令作用
ngIf 指令用于根据表达式的值,在指定位置渲染 then 或 else 模板的内容。
then 模板除非绑定到不同的值,否则默认是 ngIf 指令关联的内联模板。
else 模板除非绑定对应的值,否则默认是 null。
NgIf 指令语法
简单形式
...
使用else块
使用then和else块
使用as语法
NgIf 使用示例
@Component({
selector: 'ng-if-then-else',
template: `
show = {{show}}
`
})
class NgIfThenElse implements OnInit {
thenBlock: TemplateRef
show: boolean = true;
@ViewChild('primaryBlock')
primaryBlock: TemplateRef
@ViewChild('secondaryBlock')
secondaryBlock: TemplateRef
switchPrimary() {
this.thenBlock = this.thenBlock === this.primaryBlock ?
this.secondaryBlock : this.primaryBlohttp://ck;
}
ngOnInit() {
this.thenBlock = this.primaryBlock;
}
}
基础知识
TemplateRef
TemplateRef 实例用于表示模板对象,TemplateRef 抽象类的定义如下:
// angular\packages\core\src\linker\template_ref.ts
export abstract class TemplateRef
abstract get elementRef(): ElementRef;
abstract createEmbeddedView(context: C): EmbeddedViewRef
}
ViewContainerRef
ViewContainerRef 实例提供了 createEmbeddedView() 方法,该方法接收 TemplateRef 对象作为参数,并将模板中的内容作为容器 (comment 元素) 的兄弟元素,插入到页面中。
NgIfContext
NgIfContext 实例用于表示 NgIf 上下文。
// angular\packages\common\src\directives\ng_ifupFnlX.ts
export class NgIfContext {
public $implicit: any = null;
public ngIf: any = null;
}
NgIf 源码分析
NgIf 指令定义
@Directive({
selector: '[ngIf]' // 属性选择器 -
})
NgIf 类私有属性及构造函数
export class NgIf {
// 创建NgIfContext上下文
private _context: NgIfContext = new NgIfContext();
// 表示then模板对象
private _thenTemplateRef: TemplateRef
// 表示else模板对象
private _elseTemplateRef: TemplateRef
// 表示根据then模板创建的EmbeddedViewRef视图
private _thenViewRef: EmbeddedViewRef
// 表示根据else模板创建的EmbeddedViewRef视图
private _elseViewRef: EmbeddedViewRef
constructor(
private _viewContainer: ViewContainerRef,
templateRef: TemplateRef
this._thenTemplateRef = templateRef; // then模板的默认值为ngIf指令关联的内联模板
}
}
NgIf 类输入属性
@Input()
set ngIf(condition: any) {
this._context.$implicit = this._context.ngIf = condition;
this._updateView(); // 更新视图
}
@Input()
set ngIfThen(templateRef: TemplateRef
this._thenTemplateRef = templateRef;
this._thenViewRef = null; // 清除之前创建的视图
this._updateView();
}
@Input()
set ngIfElse(templateRef: TemplateRef
this._elseTemplateRef = templateRef;
this._elseViewRef = null; // 清除之前创建的视图
this._updateView();
}
_updateView() 私有方法
// 更新视图
private _updateView() {
// this._context.$implicit = this._context.ngIf = condition
// 若condition表达式的值为truthy
if (this._context.$implicit) {
// 若_thenViewRef为null且_thenTemplateRef存在,则创建_thenViewRef内嵌视图
if (!this._thenViewRef) {
this._viewContainer.clear();
this._elseViewRef = null;
if (this._thenTemplateRef) {
this._thenViewRef =
this._viewContainer.createEmbeddedView(this._thenTemplateRef,
upFnlX this._context);
}
}
} else { // condition表达式的值为falsy
// 若_elseViewRef为null且_elseTemplateRef存在,则创建_elseViewRef内嵌视图
if (!this._elseViewRef) {
this._viewContainer.clear();
this._thenViewRef = null;
if (this._elseTemplateRef) {
this._elseViewRef =
this._viewContainer.createEmbeddedView(this._elseTemplateRef,
this._context);
}
}
}
}
ngIf 指令的源码相对比较简单,最核心的是 _updateView() 方法。而该方法中最重要的功能就是如何基于模板对象创建内嵌视图。接下来我们来分析一下 ViewContainerRef 对象的 createEmbeddedView() 方法。
ViewContainerRef - createEmbeddedView()
方法签名
// angular\packages\core\src\linker\view_container_ref.ts
export abstract class ViewContainerRef {
/**
* 基于TemplateRef对象创建Embedded View(内嵌视图),然后根据`index`指定的值,插入到容器中。
* 如果没有指定`index`的值,新创建的视图将作为容器中的最后一个视图插入。
*/
abstract createEmbeddedView
templateRef: TemplateRef
context?: C, index?: number):
EmbeddedViewRef
}
方法实现
// angular\packages\core\src\view\refs.ts
class ViewContainerRef_ implements ViewContainerData {
// ...
createEmbeddedView
templateRef: TemplateRef
context?: C, index?: number):
EmbeddedViewRef
// 调用TemplateRef对象createEmbeddedView()方法创建EmbeddedViewRef对象
const viewRef = templateRef.createEmbeddedView(context ||
// 根据指定的index值,插入到视图容器中
this.insert(viewRef, index);
return viewRef;
}
}
// ViewContainerData接口继承于ViewContainerRef抽象类
export interface ViewContainerData extends ViewContainerRef {
_embeddedViews: ViewData[];
}
export interface ViewData {
def: ViewDefinition;
root: RootData;
renderer: Renderer2;
parentNodeDef: NodeDef|null;
parent: ViewData|null;
viewContainerParent: ViewData|null;
component: any;
context: any;
nodes: {[key: number]: NodeData};
state: ViewState;
oldValues: any[];
disposables: DisposableFn[]|null;
}
通过观察 ViewContainerRef_ 类中的 createEmbeddedView() 方法,我们发现该方法内部是调用 TemplateRef 对象的 createEmbeddedView() 方法来创建内嵌视图。因此接下来我们再来分析一下 TemplateRef 对象的 createEmbeddedView() 方法。
TemplateRef - createEmbeddedView()
方法签名
// angular\packages\core\src\linker\template_ref.ts
export abstract class TemplateRef
abstract createEmbeddedView(context: C): EmbeddedViewRef
}
方法实现
// angular\packages\core\src\view\refs.ts
class TemplateRef_ extends TemplateRef
// ...
createEmbeddedView(context: any): EmbeddedViewRef
return new ViewRef_(Services.createEmbeddedView(
this._parentView, this._def, this._def.element !.template !, context));
}
}
export interface TemplateData extends TemplateRef
_projectedViews: ViewData[];
}
看完上面的源码,毫无疑问接下来我们要继续分析 Services 对象中的 createEmbeddedView() 方法。
Services - createEmbeddedView()
Services 对象定义
// angular\packages\core\src\view\types.ts
export const Services: Services = {
setCurrentNode: undefined !,
createRootView: undefined !,
createEmbeddedView: undefined !,
createComponentView: undefined !,
createNgModuleRef: undefined !,
overrideProvider: undefined !,
clearProviderOverrides: undefined !,
checkAndUpdateView: undefined !,
checkNoChangesView: undefined !,
destroyView: undefined !,
resolveDep: undefined !,
createDebugContext: undefined !,
handleEvent: undefined !,
updateDirectives: undefined !,
updateRendereupFnlXr: undefined !,
dirtyParentQueries: undefined !,
};
Services 对象初始化
// angular\packages\core\src\view\services.ts
export function initServicesIfNeeded() {
if (initialized) {
return;
}
initialized = true;
const services = isDevMode() ? createDebugServices() : createProdServices();
Services.setCurrentNode = services.setCurrentNode;
Services.createRootView = services.createRootView;
Services.createEmbeddedView = services.createEmbeddedView;
Services.createComponentView = services.createComponentView;
Services.createNgModuleRef = services.createNgModuleRef;
Services.overrideProvider = services.overrideProvider;
Services.clearProviderOverrides = services.clearProviderOverrides;
Services.checkAndUpdateView = services.checkAndUpdateView;
Services.checkNoChangesView = services.checkNoChangesView;
Services.destroyView = services.destroyView;
Services.resolveDep = resolveDep;
Services.createDebugContext = services.createDebugContext;
Services.handleEvent = services.handleEvent;
Services.updateDirectives = services.updateDirectives;
Services.updateRenderer = services.updateRenderer;
Services.dirtyParentQueries = dirtyParentQueries;
}
在 initServicesIfNeeded() 方法中,会根据当前所处的模式,创建不同的 Services 对象。接下来 我们直接来看一下 createProdServices() 方法:
function createProdServices() {
return {
setCurrentNode: () => {},
createRootView: createProdRootView,
createEmbeddedView: createEmbeddedView // 省略了其它方法
}
createEmbeddedView() 方法
// angular\packages\core\src\view\view.ts
export function createEmbeddedView(
parent: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context?: any): ViewData {
// embedded views are seen as siblings to the anchor, so we need
// to get the parent of the anchor and use it as parentIndex.
// 创建ViewData对象
const view = createView(parent.root, parent.renderer, parent, anchorDef, viewDef);
// 初始化ViewData对象-设置component及context属性的值
initView(view, parent.component, context);
// 创建视图中的节点,即设置view.nodes数组的属性值
// const nodes = view.nodes; for(...) { ...; nodes[i] = nodeData; }
createViewNodes(view);
return view;
}
此时发现如果完整分析所有的方法,会涉及太多的内容。源码分析就到此结束,有兴趣的读者请自行阅读源码哈(请各位读者见谅)。接下来我们来总结一下 createEmbeddedView() 方法调用流程:
ViewContainerRef_ -> createEmbeddedView()
=> TemplateRef_ -> createEmbeddedView()
=> Services -> createEmbeddedView()
=> Call createEmbeddedView()
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~