您的位置:首页 > Web前端 > AngularJS

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

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

在 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
可以向传入的模板传递渲染数据,两者搭配使用可以起到很好的效果。

参考:

ng-content: The hidden docs
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: