国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

[譯] 探索 Angular 使用 ViewContainerRef 操作 DOM

wind5o / 446人閱讀

摘要:在探索抽象類(lèi)前,先了解下如何在組件指令中獲取這些抽象類(lèi)。下面示例描述在組建模板中如何創(chuàng)建如同其他抽象類(lèi)一樣,通過(guò)屬性綁定元素,比如上例中,綁定的是會(huì)被渲染為注釋的元素,所以輸出也將是。你可以使用查詢(xún)模板引用變量來(lái)獲得抽象類(lèi)。

原文鏈接:Exploring Angular DOM manipulation techniques using ViewContainerRef

如果想深入學(xué)習(xí) Angular 如何使用 Renderer 和 View Containers 技術(shù)操作 DOM,可以查閱 YouTube 視頻 my talk at NgVikings

每次我讀到 Angular 如何操作 DOM 相關(guān)文章時(shí),總會(huì)發(fā)現(xiàn)這些文章提到 ElementRefTemplateRefViewContainerRef 和其他的類(lèi)。盡管這些類(lèi)在 Angular 官方文檔或相關(guān)文章會(huì)有涉及,但是很少會(huì)去描述整體思路,這些類(lèi)如何一起作用的相關(guān)示例也很少,而本文就主要描述這些內(nèi)容。

如果你來(lái)自于 angular.js 世界,很容易明白如何使用 angular.js 操作 DOM。angular.js 會(huì)在 link 函數(shù)中注入 DOM element,你可以在組件模板里查詢(xún)?nèi)魏喂?jié)點(diǎn)(node),添加或刪除節(jié)點(diǎn)(node),修改樣式(styles),等等。然而這種方式有個(gè)主要缺陷:與瀏覽器平臺(tái)緊耦合

新版本 Angular 需要在不同平臺(tái)上運(yùn)行,如 Browser 平臺(tái),Mobile 平臺(tái)或者 Web Worker 平臺(tái),所以,就需要在特定平臺(tái)的 API 和框架接口之間進(jìn)行一層抽象(abstraction)。Angular 中的這層抽象就包括這些引用類(lèi)型:ElementRefTemplateRefViewRefComponentRefViewContainerRef。本文將詳細(xì)講解每一個(gè)引用類(lèi)型(reference type)和該引用類(lèi)型如何操作 DOM。

@ViewChild

在探索 DOM 抽象類(lèi)前,先了解下如何在組件/指令中獲取這些抽象類(lèi)。Angular 提供了一種叫做 DOM Query 的技術(shù),主要來(lái)源于 @ViewChild@ViewChildren 裝飾器(decorators)。兩者基本功能相同,唯一區(qū)別是 @ViewChild 返回單個(gè)引用,@ViewChildren 返回由 QueryList 對(duì)象包裝好的多個(gè)引用。本文示例中主要以 ViewChild 為例,并且描述時(shí)省略 @

通常這兩個(gè)裝飾器與模板引用變量(template reference variable)一起使用,模板引用變量?jī)H僅是對(duì)模板(template)內(nèi) DOM 元素命名式引用(a named reference),類(lèi)似于 html 元素的 id 屬性。你可以使用模板引用(template reference)來(lái)標(biāo)記一個(gè) DOM 元素,并在組件/指令類(lèi)中使用 ViewChild 裝飾器查詢(xún)(query)它,比如:

@Component({
    selector: "sample",
    template: `
        I am span
    `
})
export class SampleComponent implements AfterViewInit {
    @ViewChild("tref", {read: ElementRef}) tref: ElementRef;

    ngAfterViewInit(): void {
        // outputs `I am span`
        console.log(this.tref.nativeElement.textContent);
    }
}

ViewChild 裝飾器基本語(yǔ)法是:

@ViewChild([reference from template], {read: [reference type]});

上例中你可以看到,我把 tref 作為模板引用名稱(chēng),并將 ElementRef 與該元素聯(lián)系起來(lái)。第二個(gè)參數(shù) read 是可選的,因?yàn)?Angular 會(huì)根據(jù) DOM 元素的類(lèi)型推斷出該引用類(lèi)型。例如,如果它(#tref)掛載的是類(lèi)似 span 的簡(jiǎn)單 html 元素,Angular 返回 ElementRef;如果它掛載的是 template 元素,Angular 返回 TemplateRef。一些引用類(lèi)型如 ViewContainerRef 就不可以被 Angular 推斷出來(lái),所以必須在 read 參數(shù)中顯式申明。其他的如 ViewRef 不可以掛載在 DOM 元素中,所以必須手動(dòng)在構(gòu)造函數(shù)中編碼構(gòu)造出來(lái)。

現(xiàn)在,讓我們看看應(yīng)該如何獲取這些引用,一起去探索吧。

ElementRef

這是最基本的抽象類(lèi),如果你查看它的類(lèi)結(jié)構(gòu),就發(fā)現(xiàn)它只包含所掛載的元素對(duì)象,這對(duì)訪問(wèn)原生 DOM 元素很有用,比如:

// outputs `I am span`
console.log(this.tref.nativeElement.textContent);

然而,Angular 團(tuán)隊(duì)不鼓勵(lì)這種寫(xiě)法,不但因?yàn)檫@種方式會(huì)暴露安全風(fēng)險(xiǎn),而且還會(huì)讓你的程序與渲染層(rendering layers)緊耦合,這樣就很難在多平臺(tái)運(yùn)行你的程序。我認(rèn)為這個(gè)問(wèn)題并不是使用 nativeElement 而是使用特定的 DOM API 造成的,如 textContent。但是后文你會(huì)看到,Angular 實(shí)現(xiàn)了操作 DOM 的整體思路模型,這樣就不再需要低階 API,如 textContent

使用 ViewChild裝飾的 DOM 元素會(huì)返回 ElementRef,但是由于所有組件掛載于自定義 DOM 元素,所有指令作用于 DOM 元素,所以組件和指令都可以通過(guò) DI(Dependency Injection)獲取宿主元素的ElementRef 對(duì)象。比如:

@Component({
    selector: "sample",
    ...
export class SampleComponent{
      constructor(private hostElement: ElementRef) {
          //outputs ...
             console.log(this.hostElement.nativeElement.outerHTML);
      }
    ...

所以組件通過(guò) DI(Dependency Injection)可以訪問(wèn)到它的宿主元素,但 ViewChild 裝飾器經(jīng)常被用來(lái)獲取模板視圖中的 DOM 元素。然而指令卻相反,因?yàn)橹噶顩](méi)有視圖模板,所以主要用來(lái)獲取指令掛載的宿主元素。

TemplateRef

對(duì)于大部分開(kāi)發(fā)者來(lái)說(shuō),模板概念很熟悉,就是跨程序視圖內(nèi)一堆 DOM 元素的組合。在 HTML5 引入 template 標(biāo)簽前,瀏覽器通過(guò)在 script 標(biāo)簽內(nèi)設(shè)置 type 屬性來(lái)引入模板,比如:

這種方式不僅有語(yǔ)義缺陷,還需要手動(dòng)創(chuàng)建 DOM 模型,然而通過(guò) template 標(biāo)簽,瀏覽器可以解析 html 并創(chuàng)建 DOM 樹(shù),但不會(huì)渲染它,該 DOM 樹(shù)可以通過(guò) content 屬性訪問(wèn),比如:


I am span in template

Angular 采用 template 標(biāo)簽這種方式,實(shí)現(xiàn)了 TemplateRef 抽象類(lèi)來(lái)和 template 標(biāo)簽一起合作,看看它是如何使用的(譯者注:ng-template 是 Angular 提供的類(lèi)似于 template 原生 html 標(biāo)簽):

@Component({
    selector: "sample",
    template: `
        
            I am span in template
        
    `
})
export class SampleComponent implements AfterViewInit {
    @ViewChild("tpl") tpl: TemplateRef;

    ngAfterViewInit() {
        let elementRef = this.tpl.elementRef;
        // outputs `template bindings={}`
        console.log(elementRef.nativeElement.textContent);
    }
}

Angular 框架從 DOM 中移除 template 元素,并在其位置插入注釋?zhuān)@是渲染后的樣子:


    

TemplateRef 是一個(gè)結(jié)構(gòu)簡(jiǎn)單的抽象類(lèi),它的 elementRef 屬性是對(duì)其宿主元素的引用,還有一個(gè) createEmbeddedView 方法。然而 createEmbeddedView 方法很有用,因?yàn)樗梢詣?chuàng)建一個(gè)視圖(view)并返回該視圖的引用對(duì)象 ViewRef

ViewRef

該抽象表示一個(gè) Angular 視圖(View),在 Angular 世界里,視圖(View)是一堆元素的組合,一起被創(chuàng)建和銷(xiāo)毀,是構(gòu)建程序 UI 的基石。Angular 鼓勵(lì)開(kāi)發(fā)者把 UI 作為一堆視圖(View)的組合,而不僅僅是 html 標(biāo)簽組成的樹(shù)。

Angular 支持兩種類(lèi)型視圖:

嵌入視圖(Embedded View),由 Template 提供

宿主視圖(Host View),由 Component 提供

創(chuàng)建嵌入視圖

模板僅僅是視圖的藍(lán)圖,可以通過(guò)之前提到的 createEmbeddedView 方法創(chuàng)建視圖,比如:

ngAfterViewInit() {
    let view = this.tpl.createEmbeddedView(null);
}
創(chuàng)建宿主視圖

宿主視圖是在組件動(dòng)態(tài)實(shí)例化時(shí)創(chuàng)建的,一個(gè)動(dòng)態(tài)組件(dynamic component)可以通過(guò) ComponentFactoryResolver 創(chuàng)建:

constructor(private injector: Injector,
            private r: ComponentFactoryResolver) {
    let factory = this.r.resolveComponentFactory(ColorComponent);
    let componentRef = factory.create(injector);
    let view = componentRef.hostView;
}

在 Angular 中,每一個(gè)組件綁定著一個(gè)注入器(Injector)實(shí)例,所以創(chuàng)建 ColorComponent 組件時(shí)傳入當(dāng)前組件(即 SampleComponent)的注入器。另外,別忘了,動(dòng)態(tài)創(chuàng)建組件時(shí)需要在模塊(module)或宿主組件的 EntryComponents 屬性添加被創(chuàng)建的組件。

現(xiàn)在,我們已經(jīng)看到嵌入視圖和宿主視圖是如何被創(chuàng)建的,一旦視圖被創(chuàng)建,它就可以使用 ViewContainer 插入 DOM 樹(shù)中。下文主要探索這個(gè)功能。

ViewContainerRef

視圖容器就是掛載一個(gè)或多個(gè)視圖的容器。

首先需要說(shuō)的是,任何 DOM 元素都可以作為視圖容器,然而有趣的是,對(duì)于綁定 ViewContainer 的 DOM 元素,Angular 不會(huì)把視圖插入該元素的內(nèi)部,而是追加到該元素后面,這類(lèi)似于 router-outlet 插入組件的方式。

通常,比較好的方式是把 ViewContainer 綁定在 ng-container 元素上,因?yàn)?ng-container 元素會(huì)被渲染為注釋?zhuān)瑥亩粫?huì)在 DOM 中引入多余的 html 元素。下面示例描述在組建模板中如何創(chuàng)建 ViewContainer

@Component({
    selector: "sample",
    template: `
        I am first span
        
        I am last span
    `
})
export class SampleComponent implements AfterViewInit {
    @ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;

    ngAfterViewInit(): void {
        // outputs `template bindings={}`
        console.log(this.vc.element.nativeElement.textContent);
    }
}

如同其他抽象類(lèi)一樣,ViewContainer 通過(guò) element 屬性綁定 DOM 元素,比如上例中,綁定的是 會(huì)被渲染為注釋的 ng-container 元素,所以輸出也將是 template bindings={}

操作視圖

ViewContainer 提供了一些操作視圖 API:

class ViewContainerRef {
    ...
    clear() : void
    insert(viewRef: ViewRef, index?: number) : ViewRef
    get(index: number) : ViewRef
    indexOf(viewRef: ViewRef) : number
    detach(index?: number) : ViewRef
    move(viewRef: ViewRef, currentIndex: number) : ViewRef
}

從上文我們已經(jīng)知道如何通過(guò)模板和組件創(chuàng)建兩種類(lèi)型視圖,即嵌入視圖和組件視圖。一旦有了視圖,就可以通過(guò) insert 方法插入 DOM 中。下面示例描述如何通過(guò)模板創(chuàng)建嵌入視圖,并在 ng-container 標(biāo)記的地方插入該視圖(譯者注:從上文中知道是追加到ng-container后面,而不是插入到該 DOM 元素內(nèi)部)。

@Component({
    selector: "sample",
    template: `
        I am first span
        
        I am last span
        
            I am span in template
        
    `
})
export class SampleComponent implements AfterViewInit {
    @ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;
    @ViewChild("tpl") tpl: TemplateRef;

    ngAfterViewInit() {
        let view = this.tpl.createEmbeddedView(null);
        this.vc.insert(view);
    }
}

通過(guò)上面的實(shí)現(xiàn),最后的 html 看起來(lái)是:


    I am first span
    
    I am span in template

    I am last span
    

可以通過(guò) detach 方法從視圖中移除 DOM,其他的方法可以通過(guò)方法名知道其含義,如通過(guò)索引獲取視圖引用對(duì)象,移動(dòng)視圖位置,或者從視圖容器中移除所有視圖。

創(chuàng)建視圖

ViewContainer 也提供了手動(dòng)創(chuàng)建視圖 API :

class ViewContainerRef {
    element: ElementRef
    length: number

    createComponent(componentFactory...): ComponentRef
    createEmbeddedView(templateRef...): EmbeddedViewRef
    ...
}

上面兩個(gè)方法是個(gè)很好的封裝,可以傳入模板引用對(duì)象或組件工廠對(duì)象來(lái)創(chuàng)建視圖,并將該視圖插入視圖容器中特定位置。

ngTemplateOutlet 和 ngComponentOutlet

盡管知道 Angular 操作 DOM 的內(nèi)部機(jī)制是好事,但是要是有某種快捷方式就更好了啊。沒(méi)錯(cuò),Angular 提供了兩種快捷指令:ngTemplateOutletngComponentOutlet。寫(xiě)作本文時(shí)這兩個(gè)指令都是實(shí)驗(yàn)性的,ngComponentOutlet 也將在版本 4 中可用(譯者注:現(xiàn)在版本 5.* 也是實(shí)驗(yàn)性的,也都可用)。如果你讀完了上文,就很容易知道這兩個(gè)指令是做什么的。

ngTemplateOutlet

該指令會(huì)把 DOM 元素標(biāo)記為 ViewContainer,并插入由模板創(chuàng)建的嵌入視圖,從而不需要在組件類(lèi)中顯式創(chuàng)建該嵌入視圖。這樣,上面實(shí)例中,針對(duì)創(chuàng)建嵌入視圖并插入 #vc DOM 元素的代碼就可以重寫(xiě):

@Component({
    selector: "sample",
    template: `
        I am first span
        
        I am last span
        
            I am span in template
        
    `
})
export class SampleComponent {}

從上面示例看到我們不需要在組件類(lèi)中寫(xiě)任何實(shí)例化視圖的代碼。非常方便,對(duì)不對(duì)。

ngComponentOutlet

這個(gè)指令與 ngTemplateOutlet 很相似,區(qū)別是 ngComponentOutlet 創(chuàng)建的是由組件實(shí)例化生成的宿主視圖,不是嵌入視圖。你可以這么使用:

總結(jié)

看似有很多新知識(shí)需要消化啊,但實(shí)際上 Angular 通過(guò)視圖操作 DOM 的思路模型是很清晰和連貫的。你可以使用 ViewChild 查詢(xún)模板引用變量來(lái)獲得 Angular DOM 抽象類(lèi)。DOM 元素的最簡(jiǎn)單封裝是 ElementRef;而對(duì)于模板,你可以使用 TemplateRef 來(lái)創(chuàng)建嵌入視圖;而對(duì)于組件,可以使用 ComponentRef 來(lái)創(chuàng)建宿主視圖,同時(shí)又可以使用 ComponentFactoryResolver 創(chuàng)建 ComponentRef。這兩個(gè)創(chuàng)建的視圖(即嵌入視圖和宿主視圖)又會(huì)被 ViewContainerRef 管理。最后,Angular 又提供了兩個(gè)快捷指令自動(dòng)化這個(gè)過(guò)程:ngTemplateOutlet 指令使用模板創(chuàng)建嵌入視圖;ngComponentOutlet 使用動(dòng)態(tài)組件創(chuàng)建宿主視圖。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/93544.html

相關(guān)文章

  • [] 關(guān)于 Angular 動(dòng)態(tài)組件你需要知道的

    摘要:第一種方式是使用模塊加載器,如果你使用加載器的話,路由在加載子路由模塊時(shí)也是用的作為模塊加載器。還需注意的是,想要使用還需像這樣去注冊(cè)它你當(dāng)然可以在里使用任何標(biāo)識(shí),不過(guò)路由模塊使用標(biāo)識(shí),所以最好也使用相同。 原文鏈接:Here is what you need to know about dynamic components in?Angular showImg(https://se...

    lcodecorex 評(píng)論0 收藏0
  • 理解Angular2中的ViewContainerRef

    摘要:注意本文不是關(guān)于如何用編程的方式來(lái)創(chuàng)建組件的文章。在這個(gè)例子中,容器元素就是元素,模版將作為這個(gè)元素的兄弟節(jié)點(diǎn)被插入。用來(lái)演示以組件自身作為視圖容器,將組件中的模版插入視圖容器的效果。 原文鏈接:https://netbasal.com/angular-...作者:Netanel Basal譯者:而井 showImg(https://segmentfault.com/img/bVbl...

    Codeing_ls 評(píng)論0 收藏0
  • 源碼分析 @angular/cdk 之 Portal

    摘要:這些依賴(lài)對(duì)象也進(jìn)一步暴露了其設(shè)計(jì)思想。關(guān)鍵功能包括在上下文內(nèi)掛載在上下文外掛載在上下文外共享數(shù)據(jù)。在構(gòu)造必須依賴(lài),所以可以直接創(chuàng)建嵌入視圖,然后手動(dòng)強(qiáng)制執(zhí)行變更檢測(cè)。提供了兩個(gè)指令和。 @angular/material 是 Angular 官方根據(jù) Material Design 設(shè)計(jì)語(yǔ)言提供的 UI 庫(kù),開(kāi)發(fā)人員在開(kāi)發(fā) UI 庫(kù)時(shí)發(fā)現(xiàn)很多 UI 組件有著共同的邏輯,所以他們把這些共...

    BearyChat 評(píng)論0 收藏0
  • Angular操作DOM:意料之外的結(jié)果及優(yōu)化技術(shù)

    摘要:翻譯在中操作意料之外的結(jié)果及優(yōu)化技術(shù)原文鏈接作者譯者而井我最近在的一個(gè)研討會(huì)上討論了中的高級(jí)操作的話題。首先,我會(huì)介紹在中操作的工具和方法,然后再介紹一些我在研討會(huì)上沒(méi)有說(shuō)過(guò)的更高級(jí)的優(yōu)化技術(shù)。 【翻譯】在Angular中操作DOM:意料之外的結(jié)果及優(yōu)化技術(shù) 原文鏈接:https://blog.angularindepth.c... 作者:Max Koretskyi 譯者:而井 ...

    未東興 評(píng)論0 收藏0
  • 】JavaScript 框架的探索與變遷(下)

    摘要:對(duì)此沒(méi)有任何限制,它不關(guān)心這個(gè)。一種控制變化的辦法是不可改變的,持久化的數(shù)據(jù)結(jié)構(gòu)。總結(jié)檢測(cè)變化時(shí)開(kāi)發(fā)中的核心問(wèn)題,而框架們以各種方式解決這個(gè)問(wèn)題。因?yàn)榻M件內(nèi)的變化是不被允許的。 AngularJS:臟檢查 我不知道什么更新了,所以當(dāng)更新的時(shí)候,我只能檢查所有的東西。 AngularJS 類(lèi)似于 Ember,當(dāng)狀態(tài)改變的時(shí)候,必須人工去處理。但不同的是,AngularJS 從不同的角度來(lái)...

    CollinPeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<