ngzorro html源码,Angular 中 ngTemplateOutlet 的用法以及ng-zorro源码分析!
一、引言
今天看到文章:https://segmentfault.com/a/1190000015944548 。于是專門研究一下ngTemplateOutlet用法!!!!
官方定義 :
NgTemplateOutlet:?它是結(jié)構(gòu)指令,根據(jù)一個(gè)提前備好的插入一個(gè)內(nèi)嵌視圖。 你可以通過設(shè)置來給附加一個(gè)上下文對(duì)象。是一個(gè)對(duì)象,該對(duì)象的 key 可在模板中使用let語句進(jìn)行綁定。
示例:?
*我測試:? 都可承載這個(gè)指令,?但不支持
這樣的標(biāo)簽,提示:使用目的
需要要自定義標(biāo)題或頁腳的內(nèi)容。
比如編寫彈窗組件,不建議在組件模板中寫死標(biāo)題和頁腳的內(nèi)容,當(dāng)在頁面上使用該組件時(shí),?頁面可以動(dòng)態(tài)向指定組件內(nèi)占位傳入“一些內(nèi)容”,組件會(huì)把它們插入到它想要的地方!
比如ng-zorro中,也大量這樣用法,https://ng.ant.design/components/card/zh#components-card-demo-simple
二、組件自定義輸入內(nèi)容
比如在一個(gè)頁面上,引用nz-card時(shí),把主頁面上內(nèi)容插入到nz-card中去,文檔上示例代碼:
如果要編寫這樣的組件,需要考慮幾個(gè)問題,
1、如何引用主頁面上的一個(gè)模板元素? ?(?使用本地變量 #,我記得以前官方文檔叫“局部模版變量"或“模板引用變量”)
2、引用的變量如何傳遞給子組件中? ? ? (子組件定義@Input? ,使用類型為TemplateRef的變量接收)
3、子組件如何使用這個(gè)引用變量? ? ? ? ? (?在模版中,用ngTemplateOutlet? 綁定這個(gè)變量即可)
4、引用的模板元素從主頁面上來,? 如何把子組件的數(shù)據(jù)(即子組件中上下文)傳遞給這個(gè)引用元素上來?(向ngTemplateOutlet?傳入?context: myContext”)
上下文傳遞很重要。組件為了使用上的靈活,一部分內(nèi)容定義在組件之外的(即主頁面上),當(dāng)它插入到子組件中的時(shí)候,必然要顯示子組件內(nèi)的一些數(shù)據(jù),它才有意義。
ngTemplateOutlet?不僅用于綁定元素,還負(fù)責(zé)把子組件中的一個(gè)數(shù)據(jù)上下文傳遞進(jìn)去.
5、模板元素如何使用上下文? (使用 模板輸入變量let?的形式,接收上下文屬性值,再用? {{? }}語法插入值)
定義上下文數(shù)據(jù)時(shí),? myContext = { $implicit: 'World', valueInContent: "子組件內(nèi)的value" };
$implicit:是默認(rèn)導(dǎo)出值。當(dāng)let-item? 后沒=?號(hào)時(shí),item引用它。
當(dāng)?let-
valueInContent
=valueInContent?時(shí),在模板元素內(nèi)部可以插值{{valueInContent}}
參考官方文檔:
完整而精巧的小例子,包含上面5個(gè)要點(diǎn),要認(rèn)真融會(huì)貫通呀:
源碼如下:
/// 主頁面
@Component({
selector: 'app-root',
template: `
Angular's ngTemplateOutlet 完整示意-----我是主頁
Hello {{name}}! 組件內(nèi)的上下文綁定: {{valueInContent}} ....主頁面的變量綁定: {{valueInApp}}`,
})
export class AppComponent {
public valueInApp = "valueInApp :)";
}
/// 一個(gè)子組件
@Component({
selector: 'app-content',
template: `
我是子組件,下面的內(nèi)容是動(dòng)態(tài)加載 :)*ngTemplateOutlet="dynamicRef context: myContext">
`,
})
export class AppContent {
display = false;
@Input() dynamicRef: TemplateRef;
myContext = { $implicit: 'World', valueInContent: "子組件內(nèi)的value" };
}
三、ng-zorro?的組件的實(shí)現(xiàn)
支持TemplateRef參數(shù)的組件的實(shí)現(xiàn)
ng-zorro中,大量的組件的參數(shù)支持傳入模板引用,它的使用無處不在,要研究框架是如何實(shí)現(xiàn)的傳入模板引用的參數(shù)。
以nz-card為例,它的API說明:
凡是支持插入外部的模板引用的參數(shù),? ?它們的類型就是: string|TemplateRef ? ?或者? TemplateRef
翻看ng-zorro的nz-card 源碼,摘引如下,現(xiàn)在看它是不是超級(jí)簡單:
// 組件TS
@Input() nzExtra: string | TemplateRef;
// 組件HTML
{{ nzExtra }}
// 組件TS
@Input() nzActions: Array> = [];
// 組件HTML
對(duì)于TemplateRef的參數(shù),?直接用[ngTemplateOutlet]?來綁定即可。框架使用ngTemplateOutlet的方式和我們上一節(jié)看到的一樣。
我測試[ngTemplateOutlet]?不可綁定上下文,但*ngTemplateOutlet就可以,所以我們盡量使用*的格式吧!
對(duì)于string|TemplateRef的參數(shù),用*nzStringTemplateOutlet來綁定,這是什么鬼東西呢?
*nzStringTemplateOutlet探險(xiǎn)
*nzStringTemplateOutlet?是ng-zorro官方擴(kuò)展的指令,很實(shí)用且復(fù)雜的指令,它即接受string|TemplateRef的兩種參數(shù)值,插入到子組件的模板中去。
現(xiàn)在要小心翼翼的進(jìn)入源碼探險(xiǎn)之旅了!
2個(gè)知識(shí)必備:
1、構(gòu)造函數(shù)注入變量,
viewContainer代表指令的宿主元素,此處它承擔(dān)渲染容器的作用,
defalultTemplate注入的是宿主元素的內(nèi)容元素,就是上面的{{nzExtra}}部分。
// 注入viewContainer 宿主元素, 注入 defaultTemplate的 TemplateRef
constructor(private viewContainer: ViewContainerRef, private defaultTemplate: TemplateRef) {}
為什么能這樣注入變量,這得參見官方文檔:
viewContainer注入:
defalultTemplate注入:
2、動(dòng)態(tài)創(chuàng)建EmbeddedView,? 這是動(dòng)態(tài)組件時(shí),經(jīng)常要使用的函數(shù)!
this.viewContainer.createEmbeddedView( 模版引用,上下文數(shù)據(jù) ); //返回一個(gè)EmbeddedView
分析源碼邏輯
使用nzStringTemplateOutlet的情景如下,nzExtra的值:string? |? TemplateRef?兩種可能:
{{ nzExtra }}
1、首先獲得各自的 ?TemplateRef?對(duì)象。 (見上圖紅綠線)
參數(shù)為:字符串string時(shí),? ? ? ? ? ? 通過注入,? ? ? ? {{nzExtra}}??==>?defalultTemplate.
參數(shù)為:模板TemplateRef時(shí),? ? ?通過指令賦值,?把?變量nzExtra==>inputTemplate.
2、創(chuàng)建EmeddedView。
使用viewContainer.createEmbeddedView方法,? 把TemplateRef和上下文來生成View.
3、監(jiān)聽指令ngOnChanges。
4、判斷是否重新創(chuàng)建視圖。因?yàn)橛脩魟?dòng)態(tài)修改引用或上下文時(shí),整個(gè)視圖要重建!
是否重建View,就是判斷nzStringTemplateOutletContext, nzStringTemplateOutlet?是否變化
a)? 如果nzStringTemplateOutlet第一次賦值,或nzStringTemplateOutlet變化前后不都是string,?要重建視圖
b)? 如果nzStringTemplateOutletContext?的屬性shape有變化時(shí),也要重建視圖。
(注:新上下文的屬性比舊上下文屬性個(gè)數(shù)多時(shí)才變化,?若只是屬性值變化,是不用更新視圖)
5、若需要重建視圖,則重建視圖。
6、無需重建視圖,則進(jìn)一步判斷是否是TemplateRef參數(shù)情況,如果上下文數(shù)據(jù)變化了,動(dòng)態(tài)更新EmeddedView的值!
通過以上源碼,nzStringTemplateOutlet指令就可以監(jiān)聽綁定模板變化,以及上下文數(shù)據(jù)變化,更新視圖。?正由于這個(gè)指令強(qiáng)大,方便,我們?cè)谑褂胣g-zorro的組件時(shí),才倍感方便順手。
綁定上下文件的語法
最后,在ng-zorro源碼中,搜索 nzStringTemplateOutlet綁定上下文時(shí)的語法,引自nz-form-control源碼:
// ng-zorro的官方寫法
{{ nzSuccessTip }}
突然很意外,為什么不是下面這樣使用??為什么寫context就能自動(dòng)賦值到nzStringTemplateOutletContext上去??
可能這是由于Angular編譯時(shí),特殊的處理吧!
// 這個(gè)寫法編譯報(bào)錯(cuò),container 不存在nzStringTemplateOutletContext屬性
[nzStringTemplateOutletContext]="{$implicit:validateControl}“ >
{{ nzSuccessTip }}
四、它的同類指令:NgComponentOutlet
偶然看到Common?模塊中,還有NgComponentOutlet指令,根據(jù)名稱也能猜出它的作用,直接把一個(gè)組件綁定過來,此時(shí)只要傳遞一個(gè)組件的類名即可!
我想起去年編寫實(shí)時(shí)數(shù)據(jù)看板的功能時(shí),每一個(gè)看板的子組件是根據(jù)配置,動(dòng)態(tài)生成一個(gè)類的工廠函數(shù),再創(chuàng)建類view,再插入到相應(yīng)的containerview中去。
當(dāng)時(shí)以為很完美的方法,其實(shí)是繞了很多彎路,直接用NgComponentOutlet一句話不就夠了嗎,當(dāng)時(shí)真的蠢,不過看了許多文章,也沒有講到這個(gè)指令的地方。Angular的知識(shí)點(diǎn)太多太碎了呀!
總結(jié)
以上是生活随笔為你收集整理的ngzorro html源码,Angular 中 ngTemplateOutlet 的用法以及ng-zorro源码分析!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机复试专业课笔试,2017年杭州电子
- 下一篇: 免师计算机与学前教育,2014届河南免师