Angular 向组件传递模板的两种方法


Posted in Javascript onFebruary 23, 2018

最近在写一个日期选择器组件,为了满足将来可能出现的各种需求,所以需要能够高度的自定义组件的样式。为了达到这个目的,需要能够在日期选择器组件外控制每个日期格子内要显示的内容,比如,标上节假日之类的。这时候,组件的一部分模板就需要由调用方提供。

在 React 里面,这种需求挺简单的,只要实现一个 date => Element 这样的函数就好了,但是 Angular 模板是纯粹的模板,需要使用一些专门的概念才能实现这个功能。

第一种方式 <ng-content>

<ng-content> 这个标签到本文撰写时为止,还没有官方的文档,甚至连占位符都没有。但是这并不妨碍我们的使用,外国热心网友已经总结出了 <ng-content> 在现阶段的特点与作用。

基本用法

<!-- Wrapper.Component.html -->
<div>
  hello
  <ng-content></ng-content>
</div>

假设我们有一个上述的组件,然后向下面这样调用:

<wrapper>
  <span> World </span>
</wrapper>

那么最终的渲染结果将会是这样的:

<div>
  hello
  <span> World </span>
</div>

看起来就是发生了很简单的替换,但是如果在 Wrapper 中出现了多个 <ng-content> 会出现多个 <span> World </span> 吗?答案是不会的。<ng-content> 的本质只是移动元素,并不会去自动的创建传入的模板,所以就算用 ngFor 套住 <ng-content> 也不会出现很多个 <span> World </span>。如果传入的是自定义的组件,这些组件也只会被实例化一次。

进阶用法

当然,如果 <ng-content> 的功能仅仅只是这样就显得太鸡肋了,在使用 <ng-content> 的时候可以指定一个选择器,这个选择器可以捕获相符的直接子元素。例如:

<!-- Wrapper.Component.html -->
<div>
  hello
  <ng-content></ng-content>
  <hr/>
  <ng-content select="span"></ng-content>
</div>

然后像下面这样使用:

<wrapper>
  <span> World </span>
  2333
</wrapper>

最终的渲染结果将会是这样:

<div>
  hello
  2333
  <hr/>
  <span> World </span>
</div>

除了设置 ng-content 标签的 select 属性之外,还可以在子元素上使用 ngProjectAs 属性,这个属性可以让这个元素被父元素中指定的 ng-content 所捕获。举个例子:

<wrapper>
  <div ngProjectAs="span"> World </div>
  2333
</wrapper>

这次被传入的模板变成了一个 div,但是因为设置了 ngProjectAs,所以“World”会出现在分割线下方。

第二种方式 NgTemplateOutlet 指令

使用 ng-content 确实可以起到传入模板的效果,但是却有个很致命的问题,就是无法传递数据到传入的模板中。为了将数据传递到传入的模板中,就需要使用到 NgTemplateOutlet 指令。

基本使用

这个指令可以用来在模板的指定位置实例化一个 TemplateRef 对象,同时,在实例化的过程中还可以传入一个数据对象。而 TemplateRef 可以通过 ng-template 标签来创建,举个例子:

@Component({
 selector: 'ng-template-outlet-example',
 template: `
  <ng-container *ngTemplateOutlet="name; context: myContext"></ng-container>

  <ng-template #name let-name="data"><span>Hello {{name}}!</span></ng-template>
`
})
class NgTemplateOutletExample {
 myContext = {data: 'World'};
}

ng-container 是一个虚拟的元素,在这个元素上我们使用了一个 NgTemplateOutlet 指令,指定了要实例化下面的名为 name 的 ng-template。同时把 myContext 这个对象作为实例化的数据上下文传入,所以最终就会显示 “Hello World!”。值得注意的是在 ng-template 里面获取传输的数据上下文的方式:let-variableName='key'

进阶使用

接下来就要实现本文开头提到的需求了,在组件外部传入模板。还是以上面的例子为例,因为模板需要由外界作为子内容传入,所以需要我们手动来捕获模板,这里需要就需要使用 ContentChild:

@Component({
 selector: 'wrapper',
 template: `
  <ng-container *ngTemplateOutlet="name; context: myContext"></ng-container>
`
})
class NgTemplateOutletExample {
 @ContentChild(TemplateRef) name: TemplateRef<any>;
 myContext = {data: 'World'};
}

就是这么简单的改动就可以让我们的组件从外界接受模板了,来试一试:

<wrapper>
  <ng-template let-value="data">
    <span>Hello {{value}}!</span>
  </ng-template>
</wrapper>

总结

以上就是 Angular 中向组件传递模板的两种方法,其中,使用 <ng-content> 标签可以更方便的控制传入的模板在 DOM 中的位置,而 NgTemplateOutlet 可以向传入的模板传递渲染数据,两者搭配使用可以起到很好的效果。

以上所述是小编给大家介绍的Angular 向组件传递模板的两种方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Bootstrap布局组件教程之Bootstrap下拉菜单
Jun 12 Javascript
JS中检测数据类型的几种方式及优缺点小结
Dec 12 Javascript
详解用node-images 打造简易图片服务器
May 08 Javascript
JS实现unicode和UTF-8之间的互相转换互转
Jul 05 Javascript
JS动态添加元素及绑定事件造成程序重复执行解决
Dec 07 Javascript
JavaScript中join()、splice()、slice()和split()函数用法示例
Aug 24 Javascript
JavaScript常见鼠标事件与用法分析
Jan 03 Javascript
vue实现歌手列表字母排序下拉滚动条侧栏排序实时更新
May 14 Javascript
如何使用50行javaScript代码实现简单版的call,apply,bind
Aug 14 Javascript
vue - vue.config.js中devServer配置方式
Oct 30 Javascript
在vue中实现echarts随窗体变化
Jul 27 Javascript
Javascript文本框脚本实现方法解析
Oct 30 Javascript
详解Node.js中的Async和Await函数
Feb 22 #Javascript
解决webpack无法通过IP地址访问localhost的问题
Feb 22 #Javascript
webpack-dev-server远程访问配置方法
Feb 22 #Javascript
关于Webpack dev server热加载失败的解决方法
Feb 22 #Javascript
基于webpack-hot-middleware热加载相关错误的解决方法
Feb 22 #Javascript
解决Webpack 热部署检测不到文件变化的问题
Feb 22 #Javascript
webpack-dev-server自动更新页面方法
Feb 22 #Javascript
You might like
PHP技术开发微信公众平台
2015/07/22 PHP
详解PHP中websocket的使用方法
2016/09/15 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
jQuery JSON的解析方式分享
2011/04/05 Javascript
深入理解JavaScript系列(17):面向对象编程之概论详细介绍
2015/03/04 Javascript
javascript正则表达式中的replace方法详解
2015/04/20 Javascript
简单的JS时钟实例讲解
2016/01/13 Javascript
简介AngularJS中$http服务的用法
2016/02/06 Javascript
jQuery简单实现彩色云标签效果示例
2016/08/01 Javascript
AngularJS入门教程之路由与多视图详解
2016/08/19 Javascript
jQuery+HTML5实现弹出创意搜索框层
2016/12/29 Javascript
原生JS轮播图插件
2017/02/09 Javascript
基于EasyUI的基础之上实现树形功能菜单
2017/06/28 Javascript
解决VUEX刷新的时候出现数据消失
2017/07/03 Javascript
使用js获取伪元素的content实例
2017/10/24 Javascript
解析Json字符串的三种方法日常常用
2018/05/02 Javascript
Vue Element 分组+多选+可搜索Select选择器实现示例
2018/07/23 Javascript
深入理解Vue keep-alive及实践总结
2019/08/21 Javascript
基于layui的table插件进行复选框联动功能的实现方法
2019/09/19 Javascript
JavaScript对象原型链原理详解
2020/02/05 Javascript
[46:55]LGD vs Liquid 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
在Python中操作列表之List.pop()方法的使用
2015/05/21 Python
Python 基于Twisted框架的文件夹网络传输源码
2016/08/28 Python
Python基础之变量基本用法与进阶详解
2020/01/03 Python
Python 定义只读属性的实现方式
2020/03/05 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
2020/11/17 Python
python实现学生信息管理系统源码
2021/02/22 Python
HTML5时代CSS设置漂亮字体取代图片
2014/09/04 HTML / CSS
美国女士内衣在线折扣商店:One Hanes Place
2019/03/24 全球购物
精致的手工皮鞋:Shoe Embassy
2019/11/08 全球购物
希特勒的演讲稿
2014/05/23 职场文书
商场促销活动总结
2014/07/10 职场文书
2014年政协委员工作总结
2014/12/01 职场文书
话题作文之自信作文
2019/11/15 职场文书
Nginx 过滤静态资源文件的访问日志的实现
2021/03/31 Servers
MYSQL中文乱码问题的解决方案
2022/06/14 MySQL