当前位置: 首页 > news >正文

如何在 Angular 中使用 NgTemplateOutlet 创建可重用组件

简介

单一职责原则是指应用程序的各个部分应该只有一个目的。遵循这个原则可以使您的 Angular 应用程序更容易测试和开发。

在 Angular 中,使用 NgTemplateOutlet 而不是创建特定组件,可以使组件在不修改组件本身的情况下轻松修改为各种用例。

在本文中,您将接受一个现有组件并重写它以使用 NgTemplateOutlet

先决条件

要完成本教程,您需要:

  • 本地安装了 Node.js,您可以按照《如何安装 Node.js 并创建本地开发环境》进行操作。
  • 一些关于设置 Angular 项目的熟悉程度。

本教程已使用 Node v16.6.2、npm v7.20.6 和 @angular/core v12.2.0 进行验证。

步骤 1 – 构建 CardOrListViewComponent

考虑 CardOrListViewComponent,它根据其 mode'card''list' 格式中显示 items

它由一个 card-or-list-view.component.ts 文件组成:

import {Component,Input
} from '@angular/core';@Component({selector: 'card-or-list-view',templateUrl: './card-or-list-view.component.html'
})
export class CardOrListViewComponent {@Input() items: {header: string,content: string}[] = [];@Input() mode: string = 'card';}

以及一个 card-or-list-view.component.html 模板:

<ng-container [ngSwitch]="mode"><ng-container *ngSwitchCase="'card'"><div *ngFor="let item of items"><h1>{{item.header}}</h1><p>{{item.content}}</p></div></ng-container><ul *ngSwitchCase="'list'"><li *ngFor="let item of items">{{item.header}}: {{item.content}}</li></ul>
</ng-container>

这是该组件的使用示例:

import { Component } from '@angular/core';@Component({template: `<card-or-list-view[items]="items"[mode]="mode"></card-or-list-view>
`
})
export class UsageExample {mode = 'list';items = [{header: 'Creating Reuseable Components with NgTemplateOutlet in Angular',content: 'The single responsibility principle...'} // ... more items];
}

该组件没有单一职责,也不够灵活。它需要跟踪其 mode 并知道如何在 cardlist 视图中显示 items。它只能显示具有 headercontentitems

让我们通过使用模板将组件分解为单独的视图来改变这一点。

步骤 2 – 理解 ng-templateNgTemplateOutlet

为了让 CardOrListViewComponent 能够显示任何类型的 items,我们需要告诉它如何显示它们。我们可以通过给它一个模板来实现这一点,它可以用来生成 items

模板将使用 <ng-template> 和从 TemplateRefs 创建的 EmbeddedViewRefsEmbeddedViewRefs 代表具有自己上下文的 Angular 视图,是最小的基本构建块。

Angular 提供了一种使用这个从模板生成视图的概念的方法,即使用 NgTemplateOutlet

NgTemplateOutlet 是一个指令,它接受一个 TemplateRef 和上下文,并使用提供的上下文生成一个 EmbeddedViewRef。可以通过 let-{{templateVariableName}}="contextProperty" 属性在模板上访问上下文,以创建模板可以使用的变量。如果未提供上下文属性名称,它将选择 $implicit 属性。

这是一个示例:

import { Component } from '@angular/core';@Component({template: `<ng-container *ngTemplateOutlet="templateRef; context: exampleContext"></ng-container><ng-template #templateRef let-default let-other="aContextProperty"><div>$implicit = '{{default}}'aContextProperty = '{{other}}'</div></ng-template>
`
})
export class NgTemplateOutletExample {exampleContext = {$implicit: 'default context property when none specified',aContextProperty: 'a context property'};
}

这是示例的输出:

<div>$implicit = 'default context property when none specified'aContextProperty = 'a context property'
</div>

defaultother 变量由 let-defaultlet-other="aContextProperty" 属性提供。

第三步 – 重构 CardOrListViewComponent

为了使 CardOrListViewComponent 更加灵活,并允许它显示任何类型的 items,我们将创建两个结构型指令来作为模板。这些模板将分别用于卡片和列表项。

这是 card-item.directive.ts


import { Directive } from '@angular/core';@Directive({selector: '[cardItem]'
})
export class CardItemDirective {constructor() { }}

这是 list-item.directive.ts


import { Directive } from '@angular/core';@Directive({selector: '[listItem]'
})
export class ListItemDirective {constructor() { }}

CardOrListViewComponent 将导入 CardItemDirectiveListItemDirective


import {Component,ContentChild,Input,TemplateRef 
} from '@angular/core';
import { CardItemDirective } from './card-item.directive';
import { ListItemDirective } from './list-item.directive';@Component({selector: 'card-or-list-view',templateUrl: './card-or-list-view.component.html'
})
export class CardOrListViewComponent {@Input() items: {header: string,content: string}[] = [];@Input() mode: string = 'card';@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate: any;@ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate: any;}

这段代码将读取我们的结构型指令作为 TemplateRefs


<ng-container [ngSwitch]="mode"><ng-container *ngSwitchCase="'card'"><ng-container *ngFor="let item of items"><ng-container *ngTemplateOutlet="cardItemTemplate"></ng-container></ng-container></ng-container><ul *ngSwitchCase="'list'"><li *ngFor="let item of items"><ng-container *ngTemplateOutlet="listItemTemplate"></ng-container></li></ul>
</ng-container>

这是该组件的使用示例:


import { Component } from '@angular/core';@Component({template: `<card-or-list-view[items]="items"[mode]="mode"><div *cardItem>静态卡片模板</div><li *listItem>静态列表模板</li></card-or-list-view>
`
})
export class UsageExample {mode = 'list';items = [{header: '使用 NgTemplateOutlet 在 Angular 中创建可重用组件',content: '单一职责原则...'} // ... 更多项];
}

通过这些更改,CardOrListViewComponent 现在可以根据提供的模板以卡片或列表形式显示任何类型的项。目前,模板是静态的。

我们需要做的最后一件事是通过为它们提供上下文来使模板变得动态:


<ng-container [ngSwitch]="mode"><ng-container *ngSwitchCase="'card'"><ng-container *ngFor="let item of items"><ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}"></ng-container></ng-container></ng-container><ul *ngSwitchCase="'list'"><li *ngFor="let item of items"><ng-container *ngTemplateOutlet="listItemTemplate; context: {$implicit: item}"></ng-container></li></ul>
</ng-container>

这是该组件的使用示例:


import { Component } from '@angular/core';@Component({template: `<card-or-list-view[items]="items"[mode]="mode"><div *cardItem="let item"><h1>{{item.header}}</h1><p>{{item.content}}</p></div><li *listItem="let item">{{item.header}}: {{item.content}}</li></card-or-list-view>
`
})
export class UsageExample {mode = 'list';items = [{header: '使用 NgTemplateOutlet 在 Angular 中创建可重用组件',content: '单一职责原则...'} // ... 更多项];
}

有趣的是,我们使用了星号前缀和微语法来实现语法糖。这与以下代码是相同的:

<ng-template cardItem let-item><div><h1>{{item.header}}</h1><p>{{item.content}}</p></div>
</ng-template>

就是这样!我们拥有了原始功能,但现在可以通过修改模板来显示任何我们想要的内容,而 CardOrListViewComponent 的责任更少了。我们可以向项上下文中添加更多内容,比如类似于 ngForfirstlast,或者显示完全不同类型的 items

结论

在本文中,您将一个现有的组件重写,以使用 NgTemplateOutlet

如果您想了解更多关于 Angular 的内容,请查看我们的 Angular 专题页面,了解相关练习和编程项目。

相关文章:

如何在 Angular 中使用 NgTemplateOutlet 创建可重用组件

简介 单一职责原则是指应用程序的各个部分应该只有一个目的。遵循这个原则可以使您的 Angular 应用程序更容易测试和开发。 在 Angular 中&#xff0c;使用 NgTemplateOutlet 而不是创建特定组件&#xff0c;可以使组件在不修改组件本身的情况下轻松修改为各种用例。 在本文…...

改进的yolo交通标志tt100k数据集目标检测(代码+原理+毕设可用)

YOLO TT100K: 基于YOLO训练的交通标志检测模型 在原始代码基础上&#xff1a; 修改数据加载类&#xff0c;支持CoCo格式&#xff08;使用cocoapi&#xff09;&#xff1b;修改数据增强&#xff1b;validation增加mAP计算&#xff1b;修改anchor&#xff1b; 注: 实验开启weig…...

nginx 日志,压缩,https功能介绍

一&#xff0c; 自定义访问日志 &#xff08;一&#xff09;日志位置存放 1&#xff0c;格式 2&#xff0c; 级别 level: debug, info, notice, warn, error, crit, alert, emerg 3&#xff0c;示例 服务机定义 错误日志存放位置 客户机错误访问 查看错误日志 4&#xff…...

代码随想录三刷day17

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣144. 二叉树的前序遍历二、力扣145. 二叉树的后序遍历三、力扣94. 二叉树的中序遍历四、力扣144. 二叉树的前序遍历无、力扣145. 二叉树的后序遍历六、…...

postcss-px-to-viewport include属性

包含include配置的(github)&#xff1a;npm i https://github.com/evrone/postcss-px-to-viewport -S 包含include配置的(npm)&#xff1a;npm i postcss-px-to-viewport-8-with-include -S 不包含包include配置的(npm)&#xff1a;npm i postcss-px-to-viewport 看了一下这篇文…...

C++设计模式——抽象工厂模式

文章目录 抽象工厂模式的主要组成部分抽象工厂模式的一个典型例子抽象工厂模式用于其他场景抽象工厂模式与其他设计模式结合使用 C 中的抽象工厂模式是一种创建型设计模式&#xff0c;它主要用于处理对象家族的创建&#xff0c;这些对象之间可能存在一定的关联关系或属于相同的…...

Windows安装VNC连接工具并结合cpolar实现远程内网Ubuntu系统桌面

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…...

Vue3 Hooks函数使用及封装思想

一、什么是Hooks函数&#xff1f; 想象一下&#xff0c;你在做饭&#xff0c;有一些调料你经常会用到&#xff0c;比如盐、酱油和辣椒。每次做饭时&#xff0c;你都会从柜子里拿出这些调料。如果你每次用完都把它们随便放在厨房的某个角落&#xff0c;下次做饭时就可能找不到它…...

YOLOv8改进涨点,添加GSConv+Slim Neck,有效提升目标检测效果,代码改进(超详细)

目录 摘要 主要想法 GSConv GSConv代码实现 slim-neck slim-neck代码实现 yaml文件 完整代码分享 总结 摘要 目标检测是计算机视觉中重要的下游任务。对于车载边缘计算平台来说&#xff0c;巨大的模型很难达到实时检测的要求。而且&#xff0c;由大量深度可分离卷积层构…...

华为s5720s-28p-power-li-ac堆叠配置

叠物理约束&#xff1a; • 连线推荐示意图选用产品子系列中固定的一款设备做示例&#xff0c;与选择产品时指定型号的外观可能不同。示意图主要用于让用户了解相同子系列设备可以用作堆叠的端口的位置&#xff0c;以及使用不同的连线方式时如何连接设备上的端口。因此&#xf…...

c# aes加密解密私钥公钥通钥

using System.Security.Cryptography; using System.Text; namespace EncryptTest { internal class Program { static void Main(string[] args) { Console.WriteLine("Hello, World!"); string 密 EncryptAESBASE64("你…...

上拉电阻与下拉电阻、电容的作用

上拉电阻与下拉电阻 在单片机电路中&#xff0c;上拉电阻和下拉电阻都是常见的电路元件&#xff0c;它们在数字电路设计中扮演着重要的角色。它们的作用如下&#xff1a; 1. **上拉电阻**&#xff1a; - **作用**&#xff1a;当一个引脚没有外部信号时&#xff0c;上拉电阻…...

《Spring Security 简易速速上手小册》第1章 Spring Security 概述(2024 最新版)

文章目录 1.1 Spring Security 的重要性1.1.1 基础知识详解1.1.2 主要案例&#xff1a;用户认证与授权1.1.3 拓展案例 1&#xff1a;OAuth2 社交登录1.1.4 拓展案例 2&#xff1a;JWT 认证 1.2 Spring Security 的核心特性1.2.1 基础知识详解1.2.2 主要案例&#xff1a;基于角色…...

vue页面菜单权限问题解决

带锚点的url,#后面部分后端获取不到. vue的页面是带有#的路由,#后端服务获取不到,只在浏览器端有用. URL 中的哈希符号 (#) 被用来作为网页中的 锚点 使用&#xff0c;锚点的含义就是页面中的某个特定的位置&#xff0c;这个位置可以被快速找到&#xff0c;很类似于在该位置抛…...

C++面试宝典第33题:数组组成最大数

题目 给定一组非负整数nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。 示例1: 输入:nums = [10, 2] 输出:"210" 示例2: 输入:nums = [3, 30, 34, 5, 9] 输出:"…...

“影像承载初心” 国际数字影像产业园2024首届摄影沙龙诚邀您的参与!

2024年2月29日&#xff0c;树莓集团总部国际数字影像产业园将举行“影像承载初心”2024首届摄影沙龙&#xff0c;活动现场邀请摄影业内大咖与专家共聚成都文创产业园&#xff0c;探讨摄影艺术及影像未来。诚邀您的参与&#xff01; 国际数字影像产业园介绍&#xff1a; 国际数…...

【C语言】while循环语句

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…...

2024数字中国创新大赛·数据要素赛道“能源大数据应用赛”正式上线!参赛指南请查收

近日&#xff0c;由国网福建电力承办的2024数字中国创新大赛能源大数据应用赛正式上线发布。赛事按照数字中国建设、能源革命的战略要求&#xff0c;围绕能源数据要素x、能源数字技术、能源商业模式等热点设置赛题&#xff0c;诚邀社会各界为加快建成新型电力系统出谋划策&…...

react-JSX基本使用

1.目标 能够知道什么是JSX 能够使用JSX创建React元素 能够在JSX中使用JS表达式 能够使用JSX的条件渲染和列表渲染 能够给JSX添加样式 2.目录 JSX的基本使用 JSX中使用JS表达式 JSX的条件渲染 JSX的列表渲染 JSX的样式处理 3.JSX的基本使用 3.1 createElement()的问题 A. …...

学习阶段单片机买esp32还是stm32?

学习阶段单片机买esp32还是stm32? 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「stm32的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xf…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...