摘要:假設我寫了以下代碼很顯然組件將被實例化一次,但現在假如我們使用第三方庫的組件如果第三方庫能夠控制組件的生命周期,我將無法知道它被實例化了多少次。
在Angular中,組件屬于特殊的指令,它的特殊之處在于它有自己的模板(html)和樣式(css)。因此使用組件可以使我們的代碼具有強解耦、可復用、易擴展等特性。通常的組件定義如下:
demo.component.ts:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "demo-component", templateUrl: "./demo.component.html", styleUrls: ["./demo.component.scss"] }) export class DemoComponent implements OnInit { constructor() { } ngOnInit() { } }
demo.component.html:
demo-component - 我是一個簡單的組件
demo.component.scss:
.demo { padding: 10px; border: 2px solid red; h2 { margin: 0; color: #262626; } }
此時我們引用該組件,就會呈現該組件解析之后的內容:
假設現在有這樣的需求,這個組件能夠接受外部投射進來的內容,也就是說組件最終呈現的內容不僅僅是本身定義的那些,那該怎么做呢?這時就要請出本文的主角 ng-content。
簡單投射我們先從最簡單開始,在 demo.component.html 中添加
demo.component.html:
demo-component - 可嵌入外部內容的組件
demo.component.scss:
.demo { padding: 10px; border: 2px solid red; h2 { margin: 0; color: #262626; } .content { padding: 10px; margin-top: 10px; line-height: 20px; color: #FFFFFF; background-color: #de7d28; } }
為了效果展示特意將
這時我們在引用該組件時可以從外部投射內容,外部內容將在橙色區域顯示:
針對性投射我是外部嵌入的內容
如果同時存在幾個
我們先看個示例,為了區別,我再新增一個藍色區域的
demo.component.html:
demo-component - 可嵌入外部內容的組件
demo.component.scss:
.demo { padding: 10px; border: 2px solid red; h2 { margin: 0; color: #262626; } .content { padding: 10px; margin-top: 10px; line-height: 20px; color: #FFFFFF; background-color: #de7d28; &.blue { background-color: blue; } } }
引用該組件:
我是外部嵌入的內容
此時,我們將看到外部內容投射到了藍色區域:
當然,如果你將橙色區域代碼放在藍色區域代碼的后面,那么外部內容就會投射到橙色區域:
所以從上面的示例我們可以看出,如果同時存在簡單的
那么知道這個問題,我們可能會想,能不能將外部內容有針對性的投射相應的
為了處理這個問題,
直接看例子,修改后的 demo.component.html 和 demo.component.scss 如下:
demo.component.html:
demo-component - 可嵌入外部內容的組件
demo.component.scss:
.demo { padding: 10px; border: 2px solid red; h2 { margin: 0; color: #262626; } .content { padding: 10px; margin-top: 10px; line-height: 20px; color: #FFFFFF; background-color: #de7d28; &.blue { background-color: blue; } &.red { background-color: red; } &.green { background-color: green; } } }
從上面代碼可以看到,藍色區域將接收 標簽 header 那部分內容,紅色區域將接收 class為"demo2"的div 的那部分內容,綠色區域將接收 屬性name為"demo3"的div 的那部分內容,橙色區域將接收其余的外部內容(開始,我是外部嵌入的內容,結束)。
引用該組件:
開始,我是外部嵌入的內容, 我是外部嵌入的內容,我在header中 我是外部嵌入的內容,我所在div的class為"demo2"我是外部嵌入的內容demo,我所在div的屬性name為"demo3"結束
此時,我們將看到外部內容投射到了指定的
現在我們知道通過 ng-content 的 select 屬性可以指定外部內容投射到指定的
而要能正確的根據 select 屬性投射內容,有個限制就是 - 不管是 標簽 header、class為"demo2"的div還是 屬性name為"demo3"的div,這幾個標簽都是作為 組件標簽
那如果不是作為直接子節點,會是什么情況呢?我們簡單修改下引用 demo-component 組件的代碼,將 標簽header 放在一個div中,修改如下:
開始,我是外部嵌入的內容, 我是外部嵌入的內容,我在header中 我是外部嵌入的內容,我所在div的class為"demo2"我是外部嵌入的內容demo,我所在div的屬性name為"demo3"結束
此時,我們看到 標簽 header 那部分內容不再投射到藍色區域中了,而是投射到橙色區域中了。原因就是
為了解決這個問題,我們必須使用 ngProjectAs 屬性,它可以應用于任何元素上。具體如下:
開始,我是外部嵌入的內容, 我是外部嵌入的內容,我在header中 我是外部嵌入的內容,我所在div的class為"demo2"我是外部嵌入的內容demo,我所在div的屬性name為"demo3"結束
通過設置 ngProjectAs 屬性,讓 標簽header 所在的 div 指向了 select="header",此時 標簽 header 那部分內容有投射到藍色區域了:
做個試驗,先定義一個 demo-child-component 組件:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "demo-child-component", template: "我是demo-child-component組件
" }) export class DemoChildComponent implements OnInit { constructor() { } ngOnInit() { console.log("demo-child-component初始化完成!"); } }
demo-component 組件修改為:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "demo-component", template: `` }) export class DemoComponent implements OnInit { show = true; constructor() { } ngOnInit() { } }
然后在 demo-component 中 投射 demo-child-component:
此時,在控制臺我們看到打印出 demo-child-component初始化完成! 這些文字。但是當我們點擊按鈕進行切換操作時,demo-child-component初始化完成! 就不再打印了,這意味著我們的 demo-child-component 組件只被實例化了一次 - 從未被銷毀和重新創建。
為什么會出現這樣的情況呢?
出現原因這也從原理解釋了前面那個問題:如果同時存在幾個
這種行為有兩個原因:期望一致性和性能。什么 "期望的一致性" 意味著作為開發人員,可以基于應用程序的代碼,猜測其行為。假設我寫了以下代碼:
很顯然 demo-child-component 組件將被實例化一次,但現在假如我們使用第三方庫的組件:
如果第三方庫能夠控制 demo-child-component 組件的生命周期,我將無法知道它被實例化了多少次。其中唯一方法就是查看第三方庫的代碼,了解它們的內部處理邏輯。將組件的生命周期被綁定到我們的應用程序組件而不是包裝器的意義是,開發者可以掌控計數器只被實例化一次,而不用了解第三方庫的內部代碼。
性能的原因 更為重要。因為 ng-content 只是移動元素,所以可以在編譯時完成,而不是在運行時,這大大減少了實際應用程序的工作量。
解決方法為了讓組件能夠控制投射進來的子組件的實例化,我們可以通過兩種方式完成:在我們的內容周圍使用
demo-component 組件修改為:
import { Component, OnInit } from "@angular/core"; @Component({ selector: "demo-component", template: `` }) export class DemoComponent implements OnInit { @ContentChild(TemplateRef) template: TemplateRef; show = true; constructor() { } ngOnInit() { } }
然后我們將 demo-child-component 包含在 ng-template 中:
此時,我們在點擊按鈕進行切換操作時,控制臺都會打印出 demo-child-component初始化完成! 這些文字。
參考資源ng-content: The hidden docs
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93975.html
摘要:入門一前言目前來說相對于現在流行的高版本以及來說實屬是老套的前端框架了,當然這都不重要,沒有完美的框架,只有不斷優化的代碼。通過使用我們稱為指令的結構,讓瀏覽器能夠識別新的語法。使用作為輸入,而不是字符串,是區別于其它的框架的最大原因。 AngularJs 入門(一) 前言 AngularJs目前來說相對于現在流行的高版本ng2、ng4,以及Vue2.0、React來說實屬是老套的前...
摘要:延伸閱讀學習與實踐資料索引與前端工程化實踐前端每周清單半年盤點之篇前端每周清單半年盤點之與篇前端每周清單半年盤點之篇 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎關注【前端之巔】微信公眾號(ID:frontshow),及時獲取前端每周清單;本文則是對于半年來發布的前端每周清單...
摘要:前端每周清單第期微服務實踐,與,組件技巧,攻防作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 前端每周清單第 26 期:Node.js 微服務實踐,Vue.js 與 GraphQL,Angular 組件技巧,HeadlessChrome 攻防 作者:王下邀月熊 編輯:徐川...
閱讀 3328·2023-04-26 00:07
閱讀 3922·2021-11-23 10:08
閱讀 2940·2021-11-22 09:34
閱讀 859·2021-09-22 15:27
閱讀 1749·2019-08-30 15:54
閱讀 3743·2019-08-30 14:07
閱讀 913·2019-08-30 11:12
閱讀 678·2019-08-29 18:44