Angular DOM 操做
相關的APIs和類:javascript
- 查詢DOM節點
template variable ref
: 模版變量引用,至關於react中的ref
ViewChild
: 查詢DOM,返回單個元素引用ViewChildren
: 返回一個QueryList
對象,包含一系列元素
ElementRef
: 元素引用- 查詢的方式獲取,好比
@ViewChild('myInput') inputElm: ElementRef
- 依賴注入的方式,獲取宿主元素,好比
constructor(private elem: ElementRef){}
- 查詢的方式獲取,好比
TemplateRef
: 模板引用- 查詢的方式, 好比
<ng-template #tpl></ng-template>
- 查詢的方式, 好比
ViewContainerRef
: 視圖容器,包含建立angular視圖的方法和操做視圖的apisViewRef
: 視圖引用,angular最小的UI單元,建立的視圖的返回類型就是ViewRef- angular中的2種類型的視圖
- 插入式視圖
Embedded Views
- 宿主視圖
component instance views
,即組件實例視圖
- 插入式視圖
EmbeddedViewRef
: 插入式視圖引用,上面建立插入式視圖防禦的類型ComponentRef<C>
: 組件視圖引用,建立hostView時返回的類型<C>
表示組件名
示例
建立視圖並插入php
import { Component, ViewChild, TemplateRef, ViewContainerRef, ViewRef, AfterViewInit } from '@angular/core'; @Component({ selector: 'app-sample', template: ` <span>我是第一個span標籤</span> <ng-container #vc></ng-container> <span>我是第二個span標籤</span> <ng-template #tpl> <div>我是模版裏面的div標籤</div> </ng-template> ` }) export class SampleComponent implements AfterViewInit { // 查詢元素, {read: ViewContainerRef} 不能省略,由於angular沒法推斷出它是一個容器 @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef; // {read: TemplateRef} 能夠省略 @ViewChild('tpl') tpl: TemplateRef<any>; constructor() {} ngAfterViewInit() { // 建立一個插入式視圖, 通常插入式視圖都對應的是模版視圖 const tplView: ViewRef = this.tpl.createEmbeddedView(null); // 插入到容器當中 使用視圖容器操做視圖的方法insert this.vc.insert(tplView); } }
最後獲得的結果是html
<app-sample> <span>我是第一個span標籤</span> <!--template bindings={}--> <div>我是模版裏面的div標籤</div> <span>我是第二個span標籤</span> <!--template bindings={}--> </app-sample>
能夠看出 ng-container
和 ng-template
最後編譯後都變爲了註釋java
<!--template bindings={}-->
使用 ngTemplateOutlet 指令
angular爲建立插入式視圖提供了 ngTemplateOutlet
指令,這個和 router-outlet
功能相似,爲模版提供了一個進入的入口,上面的例子能夠改寫爲react
import {
Component,
} from '@angular/core';
@Component({
selector: 'app-sample',
template: `
<span>我是第一個span標籤</span> <ng-container [ngTemplateOutlet]="tpl"></ng-container> <span>我是第二個span標籤</span> <ng-template #tpl> <div>我是模版裏面的div標籤</div> </ng-template> ` }) export class SampleComponent { }
能夠看出這種十分的方便,在餓了嗎angular tooltip組件中就使用到了這個指令api
@Component({
selector: 'el-tooltip',
template: `
<div style="position: relative; display: inline-block;"> <div [class]="'el-tooltip__popper is-' + effect + ' ' + popperClass" style="left: -20000px; top: 0; position: absolute;" [@fadeAnimation]="!showPopper" [attr.x-placement]="xPlacement" #popperContent> <div x-arrow class="popper__arrow" [hidden]="!visibleArrow"></div> <ng-template [ngTemplateOutlet]="tip"></ng-template> # 此處使用到了ngTemplateOutlet指令 </div> <ng-content></ng-content> </div> `, animations: [fadeAnimation], }) export class ElTooltip implements AfterContentInit { @ContentChild('tip') tip: TemplateRef<any> }
使用時:ruby
<el-tooltip> <ng-template #tip>我是將要插入的模版內容<ng-template> </el-tooltip>
ngComponentOutlet
這個指令和上面的 ngTemplateOutlet
相似,可是它將建立一個 host view
(組件的實例),而不是插入式視圖,使用方式app
<ng-container *ngComponentOutlet="ColorComponent"></ng-container>
ViewContainerRef源碼
import { Injector } from '../di/injector'; import { ComponentFactory, ComponentRef } from './component_factory'; import { ElementRef } from './element_ref'; import { NgModuleRef } from './ng_module_factory'; import { TemplateRef } from './template_ref'; import { EmbeddedViewRef, ViewRef } from './view_ref'; /** * Represents a container where one or more Views can be attached. * 表示可以被一個或者多個視圖附着的容器 * The container can contain two kinds of Views. Host Views, created by instantiating a * {@link Component} via {@link #createComponent}, and Embedded Views, created by instantiating an * {@link TemplateRef Embedded Template} via {@link #createEmbeddedView}. * 容器可以包含2種類型的視圖: 宿主視圖(組件實例) 和 插入式視圖(使用模版建立的視圖) * The location of the View Container within the containing View is specified by the Anchor * `element`. Each View Container can have only one Anchor Element and each Anchor Element can only * have a single View Container. * * Root elements of Views attached to this container become siblings of the Anchor Element in * the Rendered View. * 插入的視圖的根元素會成爲視圖容器的兄弟節點,而不是之間插入到容器中,這點和router-outlet插入組件的方式一致 * * To access a `ViewContainerRef` of an Element, you can either place a {@link Directive} injected * with `ViewContainerRef` on the Element, or you obtain it via a {@link ViewChild} query. * 能夠經過注入的方式範圍viewContainerRef 和 經過 ViewChild 查詢的方式獲取viewContainerRef * @stable */ export declare abstract class ViewContainerRef { /** * Anchor element that specifies the location of this container in the containing View. * <!-- TODO: rename to anchorElement --> */ readonly abstract element: ElementRef; readonly abstract injector: Injector; // 注入器, 用於動態建立組件中 readonly abstract parentInjector: Injector; // 父注入器, 若是組件自身沒有提供注入器,使用父注入器 /** * Destroys all Views in this container. 銷燬容器內的全部視圖 */ abstract clear(): void; /** * Returns the {@link ViewRef} for the View located in this container at the specified index. * 返回視圖引用索引 */ abstract get(index: number): ViewRef | null; /** * 獲取視圖容器的數量 * Returns the number of Views currently attached to this container. */ readonly abstract length: number; /** * 實例化一個插入式視圖,能夠插入到指定的索引位置,若是不指定索引,將放到最後面 * Instantiates an Embedded View based on the {@link TemplateRef `templateRef`} and inserts it * into this container at the specified `index`. * * If `index` is not specified, the new View will be inserted as the last View in the container. * * Returns the {@link ViewRef} for the newly created View. 返回一個視圖引用 */ abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>; /** * 實例化單個組件,插入到宿主視圖中,能夠插入到指定的索引位置,若是不指定索引,將放到最後面 * Instantiates a single {@link Component} and inserts its Host View into this container at the * specified `index`. * * The component is instantiated using its {@link ComponentFactory} which can be * obtained via {@link ComponentFactoryResolver#resolveComponentFactory}. * 組件經過 ComponentFactory 實例化, 而組件工廠能夠經過 ComponentFactoryResolver來建立 * If `index` is not specified, the new View will be inserted as the last View in the container. * * You can optionally specify the {@link Injector} that will be used as parent for the Component. * * Returns the {@link ComponentRef} of the Host View created for the newly instantiated Component. */ abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>; /** * 插入視圖 * Inserts a View identified by a {@link ViewRef} into the container at the specified `index`. * * If `index` is not specified, the new View will be inserted as the last View in the container. * * Returns the inserted {@link ViewRef}. */ abstract insert(viewRef: ViewRef, index?: number): ViewRef; /** * 依據索引移動視圖 * Moves a View identified by a {@link ViewRef} into the container at the specified `index`. * * Returns the inserted {@link ViewRef}. */ abstract move(viewRef: ViewRef, currentIndex: number): ViewRef; /** * 返回視圖的索引位置 * Returns the index of the View, specified via {@link ViewRef}, within the current container or * `-1` if this container doesn't contain the View. */ abstract indexOf(viewRef: ViewRef): number; /** * 移除視圖 * Destroys a View attached to this container at the specified `index`. * * If `index` is not specified, the last View in the container will be removed. */ abstract remove(index?: number): void; /** * 將視圖從當前容器中分離 * Use along with {@link #insert} to move a View within the current container. * * If the `index` param is omitted, the last {@link ViewRef} is detached. */ abstract detach(index?: number): ViewRef | null; }
2種視圖
模版視圖dom
也稱之爲插入式視圖ide
<ng-template #tpl></ng-template> <ng-container #vc><ng-container> class SampleComponent implments AfterViewInit { @ViewChild('tpl') tpl: Template<any>; @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef; ngAfterViewInit() { let embeddedView: ViewRef = this.tpl.createEmbeddedView(null); this.vc.insert(embeddedView); } }
宿主視圖
和組件相關
<ng-container #vc><ng-container> class SampleComponent implments AfterViewInit { @ViewChild('tpl') tpl: Template<any>; @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef; componentRef: ComponentRef<ColorComponent>; constructor(private injector: Injector, provate cfr: ComponentFactoryResolver) {} ngAfterViewInit() { const factory = this.cfr.rosolveComponentFactory(ColorComponent); // 建立組件工廠 this.componentRef = this.vc.createComponent(factory); // 建立組件引用 // this.componentRef = factory.create(this.injector); // 建立注入器 // let view: ViewRef = componentRef.hostView; // 建立宿主視圖 // this.vc.insert(view); } }
最後動態建立的組件須要添加到 entryComponent
中
示例:
文章參考: