angular 渲染層
angular一個跨平台的框架不僅僅針對的瀏覽器這一個平台
ElementRef 與 TemplateRef
簡單的理解:
ElemnetRef : 例如一個<span>元素的引用;
TemplateRef: 例如template模板的引用;
再angular中,官方的說法是: 不推薦使用ElementRef來改變元素的樣式屬性值或者操作DOM元素,原因是,angular是一個跨平台的框架,如果直接使用ElementRef對DOM直接進行操作,那么在其他平台情況下會出事。那么真的的正規操作DOM是使用什么呢? 官方推薦: 僅使用render2來改變DOM元素的樣式,僅使用viewContentRef來改變DOM的結構,不推薦使用render2來改變DOM結構,為什么呢?
不推薦使用Render2來改變DOM結構的原因
首先了解一下angular中如何將組件轉為視圖
view 與 HTML 元素的關系
使用render2操作DOM結構,只是將DOM的標簽移除,但是在視圖中的標簽view並沒有被真的移除,這就是為什么改變DOM結構不推薦使用render2的原因
實戰
1. 使用TemplateRef關聯元素 結合render2改變元素的樣式
首先了解一下render2幾個常用API
box.component.html
<div>div 1</div> <div #targetDiv>targerDiv</div>
box.component.ts
export class BoxComponent implements OnInit, AfterViewInit {
@ViewChild('targetDiv') targetDiv: ElementRef; constructor(private _elementRef: ElementRef, private _render: Renderer2) { } ngOnInit() { } ngAfterViewInit(): void { this._render.setStyle(this.targetDiv.nativeElement, 'background', 'pink'); console.log(this._elementRef.nativeElement); console.log(this.targetDiv); } }
效果圖
2. 使用ViewContentRef創建元素
總體思路:viewContentRef引用<ng-container>標簽,<ng-container>是angular里的一種映射,在沒有真的內容出現的時候,<ng-container>只是一個隱式的占位符,最后動態生成的元素會被填充到這個占位符中,由viewContentRef的實例使用自帶的API來創建元素,元素應該是一開始就寫好的,但是其DOM結果沒有被渲染出來,在angular中<ng-template>中的內容會被忽略,我們需要做的是創建<ng-tempate>的引用,然后給到viewContentRef的實例<ng-tempate>中的元素自然會被顯示出來。
首先了解一下ViewContentRef的常用API
ViewContentRefComponent.html
<!--<ng-template><span #span>i am span to removed</span></ng-template>--> <ng-template><a>i am a to removed</a></ng-template> <ng-container #vc></ng-container> <button (click)="remove()">remove</button> <button (click)="create()">create</button>
ViewContentRefComponent.ts
export class ViewContentRefComponent implements OnInit, AfterViewInit {
// @ViewChildren('span') spanElemnet;
// @ViewChildren('a') aElement;
@ViewChild(TemplateRef) template; @ViewChild('vc', {read: ViewContainerRef}) vc; constructor() { } ngOnInit() { // console.log(this.spanElemnet); console.log(this.template); console.log(this.vc); } ngAfterViewInit(): void { this.vc.createEmbeddedView(this.template); // console.log(this.spanElemnet.length); } remove = () => { this.vc.remove(); } create = () => { this.vc.createEmbeddedView(this.template); } }
2. 使用viewContentRef創建組件
總體思路: 創建一個組件;然后再要創建組件的另外一個組建中引用ViewContainerRef,將工廠解析器解析之后的組件(被創建的組件)ViewContainerRef的創建組件函數中即可
alerComponent.html
<p>name: {{name}}</p> <p>age: {{age}}</p>
alerComponent.ts
export class AlertComponent implements OnInit {
@Input() name = ''; @Input() age = 0; constructor() { } ngOnInit() { } }
createAlert.html
<ng-template #contatiner></ng-template> <button (click)="create()">create alter component</button> <button (click)="remove()">remove component</button>
createAlert.componts.ts
export class CreateAlertComponent implements OnInit {
@ViewChild('contatiner', {read: ViewContainerRef}) contatiner; alertComponent: ComponentRef<any>; constructor(private componentFactoryResolver: ComponentFactoryResolver) { } ngOnInit() { } create = (): void => { this.contatiner.clear(); this.alertComponent = this.contatiner.createComponent(this.componentFactoryResolver.resolveComponentFactory(AlertComponent)); this.alertComponent.instance.name = 'lili'; this.alertComponent.instance.age = 12; } remove = (): void => { // 被創建的組件進行自我銷毀 this.alertComponent.destroy(); } }
最終效果,可以拉取代碼跑一下。