现在,我们写一个组件puppiesListCmp,用于显示小狗狗的列表:

//puppies-list.component.ts
@Component({
selector: 'puppies-list',
template: `
<div *ngFor="let puppy of puppies">
<span>{{puppy.name}}</span>
<span>{{puppy.age}}</span>
<span>{{puppy.color}}</span>
</div>
`
})
export class puppiesListCmp{
@Input() puppies: Puppy[];
}
interface Puppy {
name: string,
age: number,
color: string
}

然后这样使用:

//app.component.ts
@Component({
selector: 'my-app',
template: `
<puppies-list [puppies]="puppies"></puppies-list>
`
})
export class App{
puppies = [
{
name: "sam",
age: 0.6,
color: "yellow"
},
{
name: "bingo",
age: 1.5,
color: "black"
}
]
}

效果就行这样:

但是,我希望我们的puppiesListCmp组件可以满足不同的需求,比如在数据不变的情况下只显示小狗狗的name和color,就像这样:

这就是本文的重点了。我们需要实现用户自定义模板!

现在我们不写死组件的模板了,而是让用户从外部输入!

首先,我们的组件模板:

<div *ngFor="let puppy of puppies">
<span>{{puppy.name}}</span>
<span>{{puppy.age}}</span>
<span>{{puppy.color}}</span>
</div>

等价于:

<ng-template ngFor let-puppy [ngForOf]="puppies">
<div>
<span>{{puppy.name}}</span>
<span>{{puppy.age}}</span>
<span>{{puppy.color}}</span>
</div>
</ng-template>

然后,用@ContentChild(关于@ContentChild可以查看这里,需翻墙)获取到外部(相对puppiesListCmp组件而言)自定义模板,并赋给ngForTemplate。也就是说,这部分:

<div>
<span>{{puppy.name}}</span>
<span>{{puppy.age}}</span>
<span>{{puppy.color}}</span>
</div>

不再像之前那样写死在组件里了,而是由使用者在父组件中自定义,然后利用Angular的内容投射(Content Projection),投射到puppiesListCmp组件里面。就像这样:

//puppies-list.component.ts
import { Component, Input, ContentChild, TemplateRef } from '@angular/core';
import { NgForOfContext } from '@angular/common';
@Component({
selector: 'puppies-list',
template: `
<ng-template ngFor let-puppy [ngForOf]="puppies" [ngForTemplate]="tpl"></ng-template>
`
})
export class puppiesListCmp{
@Input() puppies: Puppy[];
@ContentChild(TemplateRef) tpl: TemplateRef<NgForOfContext<Puppy>>
}
interface Puppy {
name: string,
age: number,
color: string
}

这样我们的组件就算完成了。然后我们使用它:

//app.component.ts
@Component({
selector: 'my-app',
template: `
<puppies-list [puppies]="puppies">
<ng-template let-puppy>
<div>
<span>{{puppy.name}}</span>
<span>{{puppy.age}}</span>
<span>{{puppy.color}}</span>
</div>
</ng-template>
</puppies-list>
`
})

效果还是一样的:

如果我们只要显示小狗狗的name和color,只要这样写就好了:

//app.component.ts
@Component({
selector: 'my-app',
template: `
<puppies-list [puppies]="puppies">
<ng-template let-puppy>
<div>
<span>{{puppy.name}}</span>
<span>{{puppy.color}}</span>
</div>
</ng-template>
</puppies-list>
`
})

效果就像这样:

这样的组件很灵活,想要什么样的效果都可以定制,这就实现了组件的复用。

好了,本文就到此为止了。不当之处,欢迎指出!

Angular:利用内容投射向组件输入ngForOf模板的更多相关文章

  1. Angular利用@ViewChild在父组件执行子组件的方法

    代码如下: @Component({ selector: 'my-app', template: ` <step-bar #stepBar></step-bar> ` }) e ...

  2. Angular开发实践(八): 使用ng-content进行组件内容投射

    在Angular中,组件属于特殊的指令,它的特殊之处在于它有自己的模板(html)和样式(css).因此使用组件可以使我们的代码具有强解耦.可复用.易扩展等特性.通常的组件定义如下: demo.com ...

  3. 使用ng-content进行组件内容投射

    原文 https://www.jianshu.com/p/c0a39b1776c0 大纲 1.认识内容投射 2.一个简单组件 3.简单投射 4.针对性投射 5.ngProjectAs 6.代码资源 认 ...

  4. vue组件4 利用slot将内容传递给组件

    除了将数据作为prop传入到组件中,vue也允许传入HTML 父组件中的子组件:<custom-button>点我<custom-button/> custom-button子 ...

  5. 转载——利用C#自带组件强壮程序日志

    利用C#自带组件强壮程序日志   在项目正式上线后,如果出现错误,异常,崩溃等情况 我们往往第一想到的事就是查看日志 所以日志对于一个系统的维护是非常重要的 声明 正文中的代码只是一个栗子,一个非常简 ...

  6. Vue中利用$emit实现子组件向父组件通信

    Vue中利用$emit实现子组件向父组件通信 父组件 <template> <div> <p>我是父组件</p> <child :isShow=& ...

  7. EditTextPreference点击后输入框显示隐藏内容,类似密码输入(转)

    http://bbs.anzhuo.cn/thread-928131-1-1.html EditTextPreference点击后输入框显示隐藏内容,类似密码输入... [复制链接]     aski ...

  8. angular利用ui-router登录检查

    angular利用ui-router登录检查 SAP都会有这个问题,session过期或者页面被刷新的情况下应该进入登录页. 监听ui-router的satte事件可以实现当state切换的时候检查登 ...

  9. Java学习笔记之[ 利用扫描仪Scanner进行数据输入 ]

    /*********数据的输入********//**利用扫描仪Scanner进行数据输入 怎么使用扫描仪Scanner *1.放在类声明之前,引入扫描仪 import java.util.Scann ...

随机推荐

  1. python下划线作用初识

    单下划线(例:_textchar) 以单下划线做前缀的名称指定了这个名称是"私有的".在 有些 导入import * 的场景中,下一个使用你代码的人(或者你本人)会明白这个名称仅内 ...

  2. Linux 中su和sudo命令的几个注意点

    1 su与su - 的区别 1.1命令说明 su对应是是no-login shell的方式进行账号登陆,命令行的变量配置还是切换账号前的变量. su-对应的是login shell的方式进行账号登陆, ...

  3. asp.net core如何自定义端口/修改默认端口

    .net core运行的默认端口是5000,但是很多时候我们需要自定义端口.有两种方式 写在Program的Main方法里面 添加 .UseUrls() var host = new WebHostB ...

  4. MySQL主从复制-xtrabackup的使用与延时复制(附原理图)

    标签(linux): mysql 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 xtrabackup是percona公司针对MySQL开发的一款开源的物理备份工 ...

  5. kali初探:root用户打开wireshark打开失败

    启动wireshark后,报错: 该界面提示在init.lua文件中使用dofile函数禁用了使用超级用户运行wireshark.这是因为wireshark工具是使用Lua语言编写的,并且在kali ...

  6. iOS-OC、Swift 混编之桥接文件

    新建一个OC语言的项目,然后添加一个基于NSObject的Swift文件SwiftFileModel类 .swift import UIKit class SwiftFileModel: NSObje ...

  7. Oracle 12cR1 RAC 在VMware Workstation上安装(下)—静默安装

    Oracle 12cR1 RAC 在VMware Workstation上安装(下)—静默安装 1.1  静默安装 1.1.1  静默安装grid 安装之前使用脚本进行校验,确保所有的failed选项 ...

  8. SpringMVC源码情操陶冶-AbstractHandlerMapping

    分析下springmvc的HandlerMapping映射的抽象类 初始化操作 通过initApplicationContext()方法进行初始化,其一般是由父类执行ApplicationContex ...

  9. 用fiddler2调试localhost

    1.用 http://localhost. (locahost紧跟一个点号): 2.用 http://127.0.0.1. (127.0.0.1紧跟一个点号): 3.用 http://machinen ...

  10. 洛谷 [P3355] 骑士共存问题

    二分图求最大独立点集 本问题在二分图中已处理过,此处用dinic写了一遍 #include <iostream> #include <cstdio> #include < ...