Angular - 元素



Angular 提供了一种简单有效的方法来创建 Web 组件。Web 组件是原生 HTML 规范中提供的自定义 HTML 元素,用于扩展 HTML 文档的功能/标签。它可以通过 JavaScript 创建,并可在 HTML 文档中使用。JavaScript 具有创建自定义 HTML 元素的特殊方法。

使用 JavaScript 创建自定义 HTML 元素是一个冗长的过程,开发人员需要了解自定义 HTML 元素的内部机制和 Shadow DOM 概念。Angular 通过将 Angular 组件转换为 Web 组件来简化此过程,只需对组件类进行最小的更改。

让我们在本节学习如何创建自定义 HTML 组件。

创建自定义组件的步骤

步骤 1:使用 Angular CLI 创建一个普通的 Angular 应用。

ng new my-app

在此,如果 CLI 询问是否包含路由模块,请选择“否”,因为在此场景中我们不需要它。

步骤 2:使用 Angular CLI 创建组件。跳过将组件导入模块。

ng generate component my-component --skip-import

步骤 3:在 @Component 装饰器中添加 standalone 属性,并将其设置为 true。顾名思义,该组件将在构建应用程序时与必要的 Angular 代码捆绑在一起,以便该组件可以在任何 HTML 文档中工作,而无需 Angular 引导代码。

@Component({
   // ...
   standalone: true,
})
export class MyCustomComponent {
   // ...
}

步骤 4:在 @Component 装饰器中添加 encapsulation 选项,并将其设置为 ViewEncapsulation.ShadowDom。ShadowDom 选项启用 HTML 原生 ShadowDom 概念,以保留组件的样式,而不会泄漏到 HTML 文档的其他部分。

@Component({
   // ...
   encapsulation: ViewEncapsulation.ShadowDom
})
export class MyCustomComponent {
   // ...
}

步骤 5:接下来,根据规范开发组件。

步骤 6:接下来,安装 Angular 团队提供的 @angular/elements 模块。@angular/elements 模块提供将 Angular 组件创建为自定义 HTML 元素的选项。

ng add @angular/elements

步骤 7:接下来,打开 main.ts 并移除所有样板代码。

步骤 8:接下来,从 @angular/platform-browser 导入 createApplication。createApplication 将引导 Angular 应用程序。

import { createApplication } from '@angular/platform-browser';

步骤 9:接下来,从 @angular/elements 模块导入 createCustomElement。createCustomElement 将用于从 Angular 组件创建自定义 HTML 元素。

import { createCustomElement } from '@angular/elements';

步骤 10:接下来,使用 createAppliation() 方法创建应用程序,方法是输入提供程序和回调方法。回调方法将用于从 Angular 组件创建自定义 HTML 元素。

createApplication({ providers: [] }).then((appRef) => {
   // ...
});

步骤 11:实现回调方法,并使用 createCustomElement() 方法创建自定义元素。createCustomElement 接受要转换的组件和应用程序的注入器。我们可以从 createApplication() 方法返回的应用程序引用中获取注入器。

createApplication({ providers: [] }).then((appRef) => {
   const myCustomComponent = createCustomElement(
      MyCustomComponent,
      { injector: appRef.injector }
   );
});

步骤 12:接下来,使用 JavaScript 原生方法 customElements.define() 方法注册创建的自定义组件。

createApplication({ providers: [] }).then((appRef) => {
   const myCustomComponent = createCustomElement(
      MyCustomComponent,
      { injector: appRef.injector }
   );
   
   customElements.define('my-custom-comp', myCustomComponent);
});

步骤 13:接下来,使用 Angular CLI 的 build 命令构建应用程序。

ng build --configuration=production

步骤 14:构建完成后,输出文件位于 dist/my-custom-component 文件夹中。它包含以下文件(类似文件)以及 index.html 文件。

  • main.bbeaed7335f8e75c.js
  • styles.ef46db3751d8e999.css
  • polyfills.b270da5a29e91679.js
  • runtime.5f19eeacd93d937b.js

步骤 15:使用新创建的组件更新 index 文件,并检查输出是否正确。如果组件需要更改,请根据需要更新 Angular 组件并重新构建应用程序。

<!doctype html>
<html lang="en" data-critters-container>
<head>
   <meta charset="utf-8">
   <title>MyWebComponent</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="stylesheet" href="styles.ef46db3751d8e999.css">
</head>
<body>
   <!-- add you custom component -->   
   <script src="runtime.5f19eeacd93d937b.js" type="module"></script><script src="polyfills.b270da5a29e91679.js" type="module"></script><script src="main.bbeaed7335f8e75c.js" type="module"></script>
</body>
</html>

工作示例

让我们创建一个显示员工信息的组件(例如 EmpCard),并将其转换为自定义 HTML 元素。

步骤 1:使用 Angular CLI 创建一个 Angular 应用程序 emp-card-web-component。

$ ng new emp-card-web-component
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
CREATE emp-card-web-component/README.md (1073 bytes)
CREATE emp-card-web-component/.editorconfig (274 bytes)
CREATE emp-card-web-component/.gitignore (548 bytes)
CREATE emp-card-web-component/angular.json (2780 bytes)
CREATE emp-card-web-component/package.json (1053 bytes)
CREATE emp-card-web-component/tsconfig.json (901 bytes)
CREATE emp-card-web-component/tsconfig.app.json (263 bytes)
CREATE emp-card-web-component/tsconfig.spec.json (273 bytes)
CREATE emp-card-web-component/.vscode/extensions.json (130 bytes)
CREATE emp-card-web-component/.vscode/launch.json (470 bytes)
CREATE emp-card-web-component/.vscode/tasks.json (938 bytes)
CREATE emp-card-web-component/src/main.ts (214 bytes)
CREATE emp-card-web-component/src/favicon.ico (948 bytes)
CREATE emp-card-web-component/src/index.html (305 bytes)
CREATE emp-card-web-component/src/styles.css (80 bytes)
CREATE emp-card-web-component/src/app/app.module.ts (314 bytes)
CREATE emp-card-web-component/src/app/app.component.css (0 bytes)
CREATE emp-card-web-component/src/app/app.component.html (23083 bytes)
CREATE emp-card-web-component/src/app/app.component.spec.ts (940 bytes)
CREATE emp-card-web-component/src/app/app.component.ts (226 bytes)
CREATE emp-card-web-component/src/assets/.gitkeep (0 bytes)
✔ Packages installed successfully.
    Directory is already under version control. Skipping initialization of git.
 	ng new my-app

在此,如果 CLI 询问是否包含路由模块,请选择“否”,因为在此场景中我们不需要它。

步骤 2:使用 Angular CLI 创建员工组件。跳过将组件导入模块。

$ ng generate component emp-card --skip-import
CREATE src/app/emp-card/emp-card.component.css (0 bytes)
CREATE src/app/emp-card/emp-card.component.html (23 bytes)
CREATE src/app/emp-card/emp-card.component.spec.ts (567 bytes)
CREATE src/app/emp-card/emp-card.component.ts (209 bytes)

步骤 3:在 @Component 装饰器中添加 standalone 属性,并将其设置为 true。顾名思义,该组件将在构建应用程序时与必要的 Angular 代码捆绑在一起,以便该组件可以在任何 HTML 文档中工作,而无需 Angular 引导代码。

@Component({
   // ...
   standalone: true,
})
export class EmpCardComponent {
   // ...
}

步骤 4:在 @Component 装饰器中添加 encapsulation 选项,并将其设置为 ViewEncapsulation.ShadowDom。ShadowDom 选项启用 HTML 原生 ShadowDom 概念,以保留组件的样式,而不会泄漏到 HTML 文档的其他部分。

@Component({
   // ...
   encapsulation: ViewEncapsulation.ShadowDom
})
export class EmpCardComponent {
   // ...
}

步骤 5:接下来,添加两个输入属性 name 和 role,以在 HTML 元素中提供员工的姓名和角色。

export class EmpCardComponent {
   @Input() name: string = '';
   @Input() role: string = '';
}

步骤 6:组件的完整列表如下:

import { Component, Input, ViewEncapsulation } from '@angular/core';

@Component({
   selector: 'app-emp-card',
   templateUrl: './emp-card.component.html',
   styleUrls: ['./emp-card.component.css'],
   standalone: true,
   encapsulation: ViewEncapsulation.ShadowDom
})
export class EmpCardComponent {
   @Input() name: string = '';
   @Input() role: string = '';
}

步骤 7:接下来,打开组件的模板并添加标记以显示员工姓名和角色,如下所示:

<div class="card">
   <div class="container">
      <h4><b>{{ name }}</b></h4>
      <p>{{ role }}</p>
   </div>
</div>

步骤 8:接下来,打开组件的样式并添加 CSS 以在员工卡片中显示阴影。

.card {
   box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}

.card:hover {
   box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}

.container {
   padding: 2px 16px;
   max-width: 200px;
}

步骤 9:接下来,安装 Angular 团队提供的 @angular/elements 模块。@angular/elements 模块提供将 Angular 组件创建为自定义 HTML 元素的选项。

$ ng add @angular/elements
Using package manager: npm
✔ Found compatible package version: @angular/[email protected].
✔ Package information loaded.

The package @angular/[email protected] will be installed and executed.
Would you like to proceed? Yes
✔ Packages successfully installed.
Package "@angular/elements" was found but does not support schematics.

步骤 10:接下来,打开 main.ts 并移除所有样板代码。

步骤 11:接下来,从 @angular/platform-browser 导入 createApplication。createApplication 将引导 Angular 应用程序。

import { createApplication } from '@angular/platform-browser';

步骤 12:接下来,从 @angular/elements 模块导入 createCustomElement。createCustomElement 将用于从 Angular 组件创建自定义 HTML 元素。

import { createCustomElement } from '@angular/elements';

步骤 13:接下来,导入 EmpCardComponnet 组件,如下所示:

import { EmpCardComponent } from './app/emp-card/emp-card.component'

步骤 14:接下来,使用 createAppliation() 方法创建应用程序,方法是输入提供程序和回调方法。回调方法将用于从 Angular 组件创建自定义 HTML 元素。

createApplication({ providers: [] }).then((appRef) => {
   // ...
});

步骤 15:实现回调方法,并使用 createCustomElement() 方法创建自定义元素。createCustomElement 接受要转换的组件和应用程序的注入器。我们可以从 createApplication() 方法返回的应用程序引用中获取注入器。

createApplication({ providers: [] }).then((appRef) => {
   const empCard = createCustomElement(
      EmpCardComponent,
      { injector: appRef.injector }
   );
});

步骤 16:接下来,使用 JavaScript 原生方法 customElements.define() 方法注册创建的自定义组件。

createApplication({ providers: [] }).then((appRef) => {
   const empCard = createCustomElement(
      EmpCardComponent,
      { injector: appRef.injector }
   );
   
   customElements.define('emp-card', empCard);
});

步骤 17:main 文件 main.ts 的完整列表如下:

import { AppModule } from './app/app.module';

import { createApplication } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements';
import { EmpCardComponent } from './app/emp-card/emp-card.component'


createApplication({ providers: [] }).then((appRef) => {
   const empCard = createCustomElement(
      EmpCardComponent,
      { injector: appRef.injector }
   );
   
   customElements.define('emp-card', empCard);
});

步骤 18:接下来,使用 Angular CLI 的 build 命令构建应用程序。

ng build --configuration=production
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.

Initial Chunk Files           | Names         |  Raw Size | Estimated Transfer Size
main.bbeaed7335f8e75c.js      | main          |  95.37 kB |                28.59 kB
polyfills.b270da5a29e91679.js | polyfills     |  33.04 kB |                10.63 kB
runtime.5f19eeacd93d937b.js   | runtime       | 922 bytes |               526 bytes
styles.ef46db3751d8e999.css   | styles        |   0 bytes |                       -

                              | Initial Total | 129.31 kB |                39.74 kB

步骤 19:构建完成后,输出文件位于 dist/emp-card-web-component 文件夹中。它包含以下文件(类似文件)以及 index.html 文件。

  • main.bbeaed7335f8e75c.js
  • styles.ef46db3751d8e999.css
  • polyfills.b270da5a29e91679.js
  • runtime.5f19eeacd93d937b.js

步骤 20:使用新创建的组件更新 index 文件,并检查输出是否正确。

<!doctype html>
<html lang="en" data-critters-container>
<head>
   <meta charset="utf-8">
   <title>EmpCardWebComponent</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.ef46db3751d8e999.css"></head>
<body>
   <emp-card name="John" role="Angular developer"></emp-card>
   <emp-card name="Maria" role="Frontend developer"></emp-card>
   <script src="runtime.5f19eeacd93d937b.js" type="module"></script><script src="polyfills.b270da5a29e91679.js" type="module"></script><script src="main.bbeaed7335f8e75c.js" type="module"></script>
</body>
</html>

在这里,我们添加了两个不同员工详细信息的 emp-card 标签。

步骤 21:最后,在 dist/emp-card-web-component 文件夹中运行一个 http 服务器,并在浏览器中检查输出。

Employee Information

总结

正如我们所学到的,在 Angular 中创建 Web 组件非常容易。我们只需要像开发普通的 Angular 组件一样开发组件即可。一旦组件的功能开发完毕,我们需要在 main.ts 文件中添加一些引导代码,并构建应用程序以获得必要的自定义 HTNL 元素作为一堆原生 JavaScript。我们可以在任何网站上使用它,而无需 Angular。

广告