一、引言

今天看到文章:https://segmentfault.com/a/1190000015944548 。于是专门研究一下ngTemplateOutlet用法!!!!

官方定义 :

NgTemplateOutlet: 它是结构指令,根据一个提前备好的插入一个内嵌视图。 你可以通过设置来给附加一个上下文对象。是一个对象,该对象的 key 可在模板中使用let语句进行绑定。

示例:

*我测试:  都可承载这个指令, 但不支持

这样的标签,提示:

使用目的

需要要自定义标题或页脚的内容。

比如编写弹窗组件,不建议在组件模板中写死标题和页脚的内容,当在页面上使用该组件时, 页面可以动态向指定组件内占位传入“一些内容”,组件会把它们插入到它想要的地方!

比如ng-zorro中,也大量这样用法,https://ng.ant.design/components/card/zh#components-card-demo-simple

二、组件自定义输入内容

比如在一个页面上,引用nz-card时,把主页面上内容插入到nz-card中去,文档上示例代码:

如果要编写这样的组件,需要考虑几个问题,

1、如何引用主页面上的一个模板元素   ( 使用本地变量 #,我记得以前官方文档叫“局部模版变量"或“模板引用变量”)

2、引用的变量如何传递给子组件中      (子组件定义@Input  ,使用类型为TemplateRef的变量接收)

3、子组件如何使用这个引用变量          ( 在模版中,用ngTemplateOutlet  绑定这个变量即可)

4、引用的模板元素从主页面上来,  如何把子组件的数据(即子组件中上下文)传递给这个引用元素上来?(向ngTemplateOutlet 传入 context: myContext”)

上下文传递很重要。组件为了使用上的灵活,一部分内容定义在组件之外的(即主页面上),当它插入到子组件中的时候,必然要显示子组件内的一些数据,它才有意义。

ngTemplateOutlet 不仅用于绑定元素,还负责把子组件中的一个数据上下文传递进去.

5、模板元素如何使用上下文? (使用 模板输入变量let 的形式,接收上下文属性值,再用  {{  }}语法插入值)

定义上下文数据时,  myContext = { $implicit: 'World', valueInContent: "子组件内的value" };

$implicit:是默认导出值。当let-item  后没= 号时,item引用它。

当 let-

valueInContent

=valueInContent 时,在模板元素内部可以插值{{valueInContent}}

参考官方文档:

完整而精巧的小例子,包含上面5个要点,要认真融会贯通呀:

源码如下:

/// 主页面

@Component({

selector: 'app-root',

template: `

Angular's ngTemplateOutlet 完整示意-----我是主页

Hello {{name}}! 组件内的上下文绑定: {{valueInContent}} ....
主页面的变量绑定: {{valueInApp}}

`,

})

export class AppComponent {

public valueInApp = "valueInApp :)";

}

/// 一个子组件

@Component({

selector: 'app-content',

template: `

我是子组件,下面的内容是动态加载 :)

*ngTemplateOutlet="dynamicRef context: myContext">

`,

})

export class AppContent {

display = false;

@Input() dynamicRef: TemplateRef;

myContext = { $implicit: 'World', valueInContent: "子组件内的value" };

}

三、ng-zorro 的组件的实现

支持TemplateRef参数的组件的实现

ng-zorro中,大量的组件的参数支持传入模板引用,它的使用无处不在,要研究框架是如何实现的传入模板引用的参数。

以nz-card为例,它的API说明:

凡是支持插入外部的模板引用的参数,   它们的类型就是: string|TemplateRef    或者  TemplateRef

翻看ng-zorro的nz-card 源码,摘引如下,现在看它是不是超级简单:

// 组件TS

@Input() nzExtra: string | TemplateRef;

// 组件HTML

{{ nzExtra }}

// 组件TS

@Input() nzActions: Array> = [];

// 组件HTML

对于TemplateRef的参数, 直接用[ngTemplateOutlet] 来绑定即可。框架使用ngTemplateOutlet的方式和我们上一节看到的一样。

我测试[ngTemplateOutlet] 不可绑定上下文,但*ngTemplateOutlet就可以,所以我们尽量使用*的格式吧!

对于string|TemplateRef的参数,用*nzStringTemplateOutlet来绑定,这是什么鬼东西呢?

*nzStringTemplateOutlet探险

*nzStringTemplateOutlet 是ng-zorro官方扩展的指令,很实用且复杂的指令,它即接受string|TemplateRef的两种参数值,插入到子组件的模板中去。

现在要小心翼翼的进入源码探险之旅了!

2个知识必备:

1、构造函数注入变量,

viewContainer代表指令的宿主元素,此处它承担渲染容器的作用,

defalultTemplate注入的是宿主元素的内容元素,就是上面的{{nzExtra}}部分。

// 注入viewContainer 宿主元素, 注入 defaultTemplate的 TemplateRef

constructor(private viewContainer: ViewContainerRef, private defaultTemplate: TemplateRef) {}

为什么能这样注入变量,这得参见官方文档:

viewContainer注入:

defalultTemplate注入:

2、动态创建EmbeddedView,  这是动态组件时,经常要使用的函数!

this.viewContainer.createEmbeddedView( 模版引用,上下文数据 ); //返回一个EmbeddedView

分析源码逻辑

使用nzStringTemplateOutlet的情景如下,nzExtra的值:string  |  TemplateRef 两种可能:

{{ nzExtra }}

1、首先获得各自的  TemplateRef 对象。 (见上图红绿线)

参数为:字符串string时,            通过注入,        {{nzExtra}}  ==> defalultTemplate.

参数为:模板TemplateRef时,     通过指令赋值, 把 变量nzExtra==>inputTemplate.

2、创建EmeddedView。

使用viewContainer.createEmbeddedView方法,  把TemplateRef和上下文来生成View.

3、监听指令ngOnChanges。

4、判断是否重新创建视图。因为用户动态修改引用或上下文时,整个视图要重建!

是否重建View,就是判断nzStringTemplateOutletContext, nzStringTemplateOutlet 是否变化

a)  如果nzStringTemplateOutlet第一次赋值,或nzStringTemplateOutlet变化前后不都是string, 要重建视图

b)  如果nzStringTemplateOutletContext 的属性shape有变化时,也要重建视图。

(注:新上下文的属性比旧上下文属性个数多时才变化, 若只是属性值变化,是不用更新视图)

5、若需要重建视图,则重建视图。

6、无需重建视图,则进一步判断是否是TemplateRef参数情况,如果上下文数据变化了,动态更新EmeddedView的值!

通过以上源码,nzStringTemplateOutlet指令就可以监听绑定模板变化,以及上下文数据变化,更新视图。 正由于这个指令强大,方便,我们在使用ng-zorro的组件时,才倍感方便顺手。

绑定上下文件的语法

最后,在ng-zorro源码中,搜索 nzStringTemplateOutlet绑定上下文时的语法,引自nz-form-control源码:

// ng-zorro的官方写法

{{ nzSuccessTip }}

突然很意外,为什么不是下面这样使用? 为什么写context就能自动赋值到nzStringTemplateOutletContext上去??

可能这是由于Angular编译时,特殊的处理吧!

// 这个写法编译报错,container 不存在nzStringTemplateOutletContext属性

[nzStringTemplateOutletContext]="{$implicit:validateControl}“ >

{{ nzSuccessTip }}

四、它的同类指令:NgComponentOutlet

偶然看到Common 模块中,还有NgComponentOutlet指令,根据名称也能猜出它的作用,直接把一个组件绑定过来,此时只要传递一个组件的类名即可!

我想起去年编写实时数据看板的功能时,每一个看板的子组件是根据配置,动态生成一个类的工厂函数,再创建类view,再插入到相应的containerview中去。

当时以为很完美的方法,其实是绕了很多弯路,直接用NgComponentOutlet一句话不就够了吗,当时真的蠢,不过看了许多文章,也没有讲到这个指令的地方。Angular的知识点太多太碎了呀!

ngzorro html源码,Angular 中 ngTemplateOutlet 的用法以及ng-zorro源码分析!相关推荐

  1. fortran中call的用法_手写源码系列(一)——call、apply、bind

    什么是手写源码 平时面试时经常会遇到让手写一个已有方法的实现,其实面试官是想考察你对于JS底层逻辑是否熟悉,经常面试会出的会在下面: call.apply.bind promise requireJS ...

  2. Angular中修改第三方组件的样式 - zorro日期选择器右端不对齐的BUG

    在一列上同时使用zorro的日期选择器和input组件会出现右端不对齐的BUG(nzSpan设置为一样) 上图中3个表单项:单据日期.开票.交货方式,nzSpan数值是一样的,可以看到日期选择器和下面 ...

  3. ngzorro html源码,angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)

    使用 NG ZORRO 在上一篇文章中,我们已经安装了NG ZORRO,并在跟模块中引入了,在子模块中使用还需要再次引入. 编辑layout模块中的header组件 在layout.module.ts ...

  4. 您需要了解有关Angular中的ng-template,ng-content,ng-container和* ngTemplateOutlet的所有信息...

    It was one of those days when I was busy working on new features for my office project. All a sudden ...

  5. python处理回显_Python中getpass模块无回显输入源码解析

    本文主要讨论了python中getpass模块的相关内容,具体如下. getpass模块 昨天跟学弟吹牛b安利Python标准库官方文档的时候偶然发现了这个模块.仔细一看内容挺少的,只有两个主要api ...

  6. 【Android 内存优化】Android 原生 API 图片压缩原理 ( 图片质量压缩方法 | 查找 Java 源码中的 native 方法对应的 C++ 源码 )

    文章目录 一. 图片质量压缩方法 二. 查找对应的 Native 方法源码 三. 分析 Bitmap.cpp 中动态注册 Native 方法 在博客 [Android 内存优化]图片文件压缩 ( An ...

  7. python删除链表中重复的节点_Java编程删除链表中重复的节点问题解决思路及源码分享...

    一. 题目 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 二. 例子 输入链表:1->2->3->3->4->4-&g ...

  8. java中arraycopy的用法_[jdk源码阅读系列]Java中System.arraycopy()的用法

    本文转载,原文链接: 3分钟了解Java中System.arraycopy的用法 - 伊万夫斯基 - 博客园  https://www.cnblogs.com/benjieqiang/p/114288 ...

  9. chrome浏览器开发者工具F12中某网站的sources下的源码如何批量保存?

    目录 chrome浏览器 开发者工具F12中某网站的sources下的源码如何批量保存 1. 常用保存Sources源码的两种方法 1.1单个文件 1.2 单个页面 2. 问题 3.解决方案 chro ...

最新文章

  1. Linux目录读写和可执行权限
  2. flask_sqlalchemy 多对多 关系 对中间表的操作
  3. 【转载】同步和互斥的POSIX支持(互斥锁,条件变量,自旋锁)
  4. 如何利用火狐获取网址中的提交链接
  5. 几个改变世界的java工具
  6. VALSE学习(七):跨媒体分析-Cross-Media Analysis and Intelligence
  7. [原创] 测试策略是什么?
  8. 美赛常用查数据查文献网站
  9. bitvise ssh client 连接linux,推荐SSH客户端Bitvise SSH Client
  10. fcitx-configtool
  11. 在线思维导图制作教程 有哪些制作思维导图的工具?
  12. pip升级及关于pyecharts安装下载所遇到的问题及部分的解决
  13. 数字转型遇阻 ,Riverbed重塑APM工具
  14. Holt Winter时间序列模型
  15. 微信小程序:uni-app云开发的网盘助手
  16. PHP在线发信投稿系统网站程序
  17. 计算机连上网没网络连接,网络显示已连接上但是无法上网如何解决
  18. Linux下minicom配置
  19. 手机页面出现乱码几种可能
  20. Mac出现异常,如何在M1或Intel Mac上重置NVRAM

热门文章

  1. Android 实现扑克牌动画,android – 重叠图像(扑克牌)
  2. 这张磁盘有写保护_u盘被写保护怎么解除 磁盘被写保护怎么解除
  3. jqury ajax跳转界面,jquery ajax 界面跳转失败解决方案
  4. java自带的xml解析,使用Java自带SAX工具解析XML
  5. 编写jmeter测试用例_JMeter 编写接口测试用例遇到的问题及解决
  6. mongodb 备份mysql_MongoDB备份与恢复
  7. 绝对好文:嵌入式系统的软件架构设计!
  8. php 价钱计算,php公式计算
  9. markdown 换行_markdown傻瓜指南(github)
  10. PHP常用方法很有意义的博客网址