Angular 18+ 高级教程 – Component 组件 の Angular Component vs Web Component
前言
在 初识 Angular 中我有提到, Angular 团队是一群不爱创新、爱 follow 标准、爱小题大做的一群人。
所以,要理解 Angular Component,我们就非得要先搞懂远古的 Web Component 和 MVVM 的概念。
MVVM 和 Web Component
关于 MVVM 可以大约翻看这篇.
简单说一下,MVVM 就是让我们尽量不要像 jQuery 年代那样直接操作 DOM,而是通过框架提供的接口,间接的去操作 DOM。
为什么要这样?
第一是,操作 DOM 的代码很繁琐不好理解。你要可读性高,本来就需要封装成声明式,而现在框架就替你封装好了。
第二是,Angular 是框架,它控制了很多底层的东西,你如果绕过它,直接控制底层,一不小心就会和它撞上。所以 best practice 总是告诉你,尽量不要直接操作 DOM。
注:不要误会哦。它是说不要直接操作,但我们可以间接操作(使用 Angular 开放好的接口)。还有 "尽量" 不代表完全不要,只是要可控就可以了。
关于 Web Component,请务必先读完 DOM – Web Components 这篇,因为下面我会用到里面的例子,继续展开。
用 Angular Component 重写 Counter Component
在 DOM – Web Components 文章的结尾,我写了一个 Counter Component,我们现在用 Angular 重写一遍。
最终效果是这样
Step by Step
follow Angular 复习与进阶系列 – Get Started 搭建一个测试环境(这里我就不使用 inline style 和 inline template了,我不喜欢。)
ng new my-app --style=scss --routing=false --skip-tests --ssr=false
创建 Counter Component
cd src/app
ng g c counter
进入 counter.component.ts, 它目前长这样
CounterComponent 是一个类,我们要用它来描述下面这个 UI 组件。(Thinking in Angular Way)
以面向对象的方式来看,中间的号码可以用一个属性(property)来表示。
左右加减可以改变中间的号码,它们可以用方法(method)来表示。
所以,添加 number 属性和 add、minus 方法到 CounterComponent 里。


export class CounterComponent {
number = 0; minus() {
this.number--;
} plus() {
this.number++;
}
}
class 搞定,接下来我们进入 counter.component.html
先给它一个初始 HTML
<button>-</button>
<span>1</span>
<button>+</button>
我们要让它和刚才的 CounterComponent 对象,关联起来。
<span>{{ number }}</span>
这个是 Angular 其中一种关联语法。{{ number }} 就是对象里的 number 属性。
接着是左右按钮的点击事件,它们要关联到对象里的 add minus 方法。
<button (click)="minus()">-</button>
<span>{{ number }}</span>
<button (click)="plus()">+</button>
注:这个环节我们先不去探讨这些关联语法 binding syntax。我们继续往下。
接着就是加入 style
添加 class 到 HTML 作为 CSS selector
<button class="minus" (click)="minus()">-</button>
<span class="number">{{ number }}</span>
<button class="plus" (click)="plus()">+</button>
进入 counter.component.scss


:host {
display: flex;
gap: 16px; :is(.minus, .plus) {
width: 64px;
height: 64px;
} .number {
width: 128px;
height: 64px;
border: 1px solid gray;
font-size: 36px;
display: grid;
place-items: center;
}
}
没什么值得关注点,只是一些美观的 styles 而已。
至此,Counter Component 的部分就算完成了。
接着是如何使用它,我们进入到 app.component.ts。
import CounterComponent 到 AppComponent 中。
任何组件内想使用其它组件都必须先 import。
接着到 app.component.html
<app-counter></app-counter>
"app-" 是所有组件的 prefix,如果你不喜欢,可以通过 angular.json 做设置。
最后跑起来
ng serve --open
效果
对比 Angular Component 和 Web Component 实现的 Counter 组件
通过对比,我们可以看出 Angular 团队在设计 Angular Component 的思路,它们如何看待 Web Component 的缺陷,如何保留 Web Component 的设计理念,如何完善 Web Component。
最终保留了什么,丢弃了什么,增加了什么。搞清楚这些对学习和使用 Angular 非常重要,正所谓 Thinking in Angular Way 就是这样来的。
我们先理一下 Web Component 的整个流程
1. 定义 CounterComponent class
2. 做 Shadow DOM 隔离 CSS
3. 拦截初始化,通过 ajax 获取 template(如果你可以接受直接写 Raw HTML 在 TS 则可以省略掉这一步...)
4. 搞事件监听和渲染(DOM 操作)
5. define and use
上面 5 个 steps,Angular 都实现了。只是大部分实现代码都被隐藏了起来,我们主要写的是声明代码。
短短的几行代码,Angular 就 "声明" 了以下 4 个 steps
1. 定义 CounterComponent class
@Component 表示这个 class 是 Component
2. 做 Shadow DOM 隔离 CSS
Angular by default 所有 Component 都是隔离 CSS 的,不过它并不是通过 Shadow DOM 实现的。之后的教程会详细讲到。
3. 拦截初始化,通过 ajax 获取 template
Angular 是在 compile time 去链接 .html file 的,而 @Component.templateUrl 声明了 file 的位置。
5. define and use
@component.selector 声明了匹配的 selector
上面几个步骤, 我们都不需要写实现代码,只写声明代码就可以了。其它的交给 Angular。
还有一步是
4. 搞事件监听和渲染(DOM 操作)
这一步,Angular 用 MVVM 的方式来 "声明"。
同样的,我们不需要写任何操作 DOM 的代码。只要 "声明" 就可以了。.
从这些对比中,我们可以体会到,Angular 的设计理念就是尽可能把 "实现代码" 转换成 "声明代码"。
这个动机很好理解,一个长期维护的项目,代码分三种。
1. 实现代码
2. 可读性代码
3. 管理代码
实现代码就是让逻辑跑起来的代码。它们的特色就是繁琐、啰嗦、可读性差、难修改。
可读性代码就是我们声明的变量、方法名、类、接口等等。它们只是为了 "好读",你随便取名字并不影响程序的执行。
管理代码就是我们为了方便维护、修改、扩展、而做的各种封装代码。
项目越小,越不重视可读性代码和管理代码。而 Angular 的定位是长期维护的大项目,所以它的方向一定是让开发人员尽可能减少实现代码,提升可读性和管理代码。
Angular Component !== Web Component
Angular Component 虽然很大程度上借鉴了 Web Component,但是 Angular 并不是用 Shadow DOM + Custom Element 来实现 Web Component 的哦。
Angular 有一个扩展叫 Angular elements,它的方向是 convert Angular Component to 正真的 Web Component。也就是 Shadow Dom + Custom Element。
但目前这个项目有很多缺失的功能,而且没有得到足够的重视。希望未来不会被砍掉呗...
目录
上一篇 Angular 18+ 高级教程 – Dependency Injection 依赖注入
下一篇 Angular 18+ 高级教程 – Component 组件 の Angular Component vs Custom Elements
想查看目录,请移步 Angular 18+ 高级教程 – 目录
喜欢请点推荐,若发现教程内容以新版脱节请评论通知我。happy coding
Angular 18+ 高级教程 – Component 组件 の Angular Component vs Web Component的更多相关文章
- Angular CLI 使用教程指南参考
Angular CLI 使用教程指南参考 Angular CLI 现在虽然可以正常使用但仍然处于测试阶段. Angular CLI 依赖 Node 4 和 NPM 3 或更高版本. 安装 要安装Ang ...
- 示例可重用的web component方式组织angular应用模块
在online web应用中,经常有这样的需求,能够让用户通过浏览器来输入代码,同时能够根据不同的代码来做语法高亮.大家已知有很多相应的javascript库来实现语法高亮的功能,比如codemirr ...
- angular custom Element 自定义web component
angular 自定义web组件: 首先创建一个名为myCustom的组件. 引入app.module: ... import {customComponent} from ' ./myCustom. ...
- Vue教程:组件Component详解(六)
一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功 ...
- angular2 学习笔记 ( Component 组件)
refer : https://angular.cn/docs/ts/latest/guide/template-syntax.html https://angular.cn/docs/ts/late ...
- 一篇文章看懂angularjs component组件
壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中详细介绍了directive基本用法与完整属性介绍.directive是个很神奇的存在,你可以不设置templa ...
- Angular 英雄示例教程
英雄指南教程(Tour of Heroes)涵盖了 Angular 的基本知识. 在本教程中,你将构建一个应用,来帮助人事代理机构来管理一群英雄. 这个入门级 app 包含很多数据驱动的应用所需的特性 ...
- [从 0 开始的 Angular 生活]No.38 实现一个 Angular Router 切换组件页面(一)
前言 今天是进入公司的第三天,为了能尽快投入项目与成为团队可用的战力,我正在努力啃官方文档学习 Angular 的知识,所以这一篇文章主要是记录我如何阅读官方文档后,实现这个非常基本的.带导航的网页应 ...
- NgRx/Store 4 + Angular 5使用教程
这篇文章将会示范如何使用NgRx/Store 4和Angular5.@ngrx/store是基于RxJS的状态管理库,其灵感来源于Redux.在NgRx中,状态是由一个包含action和reducer ...
- angular里使用vue/vue组件怎么在angular里用
欢迎加入前端交流群交流知识&&获取视频资料:749539640 如何在angularjs(1)中使用vue参考: https://medium.com/@graphicbeacon/h ...
随机推荐
- Nuxt.js 错误侦探:useError 组合函数
title: Nuxt.js 错误侦探:useError 组合函数 date: 2024/7/14 updated: 2024/7/14 author: cmdragon excerpt: 摘要:文章 ...
- 如何查看Chrome内核版本
Blink Google chrome即谷歌浏览器原来采用的渲染引擎是Webkit,自chrome 28开始,谷歌浏览器放弃了Webkit,改用自主开发的渲染引擎Blink. 所以现在大多数喜欢尝鲜的 ...
- thinkphp5 关于跨域的一些坑
1.首先在tp5的入口文件:public/index.php 在里面添加三行: // [ 应用入口文件 ] header("Access-Control-Allow-Origin:*&quo ...
- webpack4.15.1 学习笔记(九) — 11个基础的插件使用
目录 html-webpack-plugin clean-webpack-plugin webpack-manifest-plugin HotModuleReplacementPlugin(内置) m ...
- 使用了条件三元运算符来判断 this.temp.id 是否存在且 mt_qty 是否已被赋值
mt_qty: (this.temp.id && this.temp.mt_qty) ? this.temp.mt_qty : event.wo_wip,在这个修正后的代码中,使用了条 ...
- nacos:关于注册服务与配置管理
为什么要用nacos做配置中心? 1.nacos可以做到统一管理,而且在修改时可以做到动态管理,无需重启即可生效. 2.nacos通过namespace进行环境隔离, 约定: namespace:用于 ...
- python修改类属性
python修改类属性 1,当类属性为不可变的值时,不可以通过实例对象去修改类属性 class Foo(object): x = 1.5 foo = Foo() print(foo.x) #输出:1. ...
- Android studio报错:Failed to allocate a 3213123 byte allocation with 31231 free bytes and 189MB ontil 0OM
这个问题是运行内存超了 在AndroidManifest中加入 android:hardwareAccelerated="false"android:largeHeap= &quo ...
- 代码随想录Day1
704.二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. 示例 1: ...
- 对比python学julia(第一章)--(第二节)似曾相识燕归来
Julia和python一样,都是跨平台开源语言,而且都是动态语言,所以毫无疑问,需要运行时支撑.很简单,到官网去下载julia(https://julialang.org/downloads/).和 ...