[Angular 基础] - Angular 渲染过程 组件的创建

[Angular 基础] - Angular 渲染过程 & 组件的创建

之前的笔记为了推进度写的太笼统了(只有功能没有其他),当时学的时候知道是什么东西,但是学完后重新复习发现有些内容就记不清了,所以重新用自己的语言总结一下

安装 angular-cli 的指令为:

# 如果不确定是否有安装过,可以先卸载
npm uninstall -g angular-cli @angular/cli
# 重新安装 CLI
npm install -g @angular/cli

Angular 项目启动挂载过程

不涉及到 webpack/vite 编译,只是简单的加载过程

首先看一下 angular 项目的架构:

❯ tree --gitignore
.
├── README.md
├── angular.json
├── package-lock.json
├── package.json
├── src
│   ├── app
│   │   ├── app.component.css
│   │   ├── app.component.html
│   │   ├── app.component.spec.ts
│   │   ├── app.component.ts
│   │   └── app.module.ts
│   ├── assets
│   ├── favicon.ico
│   ├── index.html
│   ├── main.ts
│   └── styles.css
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json4 directories, 16 files

其中 src 外面的代码都是配置代码,一般来说没有什么变更的需要,目前我能想到的变动的情况只有添加额外的 CSS 库需要变动 angular.json

src 里面则是实现的代码,这里面 index.html 的作用就是一个锚点,也就是组件在没有渲染时的初始界面,内容如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><title>MyFirstApp</title><base href="/" /><meta name="viewport" content="width=device-width, initial-scale=1" /><link rel="icon" type="image/x-icon" href="favicon.ico" /></head><body><app-root></app-root></body>
</html>

这与没有被 JS 重写的 HTML 一致:

在这里插入图片描述

下面的 script 也是在编译的时候添加到 HTML 网页中,具体的配置依旧在 angular.json 中:

{// 省略其他"options": {"outputPath": "dist/my-first-app","index": "src/index.html","browser": "src/main.ts","polyfills": ["zone.js"],"tsConfig": "tsconfig.app.json","assets": ["src/favicon.ico", "src/assets"],"styles": ["node_modules/bootstrap/dist/css/bootstrap.min.css","src/styles.css"],"scripts": []}
}

这里 main.ts 就是项目中 JS 文件的入口,其中主要的作用就是挂在对应的组件:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';// 这个作用类似于 React 中的 <App />
import { AppModule } from './app/app.module';// 这个作用类似于 ReactDOM.render(<App />, el);
platformBrowserDynamic().bootstrapModule(AppModule).catch((err) => console.error(err));

AppModule 就是一个 Angular 的组件

组件

首先过一下什么是 Angular 组件(component),抛开具体的实现,单纯从概念上来说,React, Angular 和 Vue 的组件都是一样的:

  • 模块化的代码

    可复用的最小代码块

  • 对数据进行处理

    最简单的例子就是通过 AJAX 获取数据后渲染给用户看

  • 对用户交互进行反应

    这点也可以和上一点进行联动,如用户提供了数据之后,组件会对数据进行处理,并且处理过的数据重新渲染在 UI 上

核心概念虽然是一致的,不过具体的实现,如使用的模板——React 使用 JSX,Angular 使用 HTML template、生命周期、组件内传递数据的方式等则会有所不同。

组件的组成

首先看一下 Angular 项目的 src 结构:

❯ tree src
src
├── app
│   ├── app.component.css
│   ├── app.component.html
│   ├── app.component.spec.ts
│   ├── app.component.ts
│   └── app.module.ts
├── assets
├── favicon.ico
├── index.html
├── main.ts
└── styles.css3 directories, 9 files

这个项目是通过 ng new my-first-app --no-strict --standalone false --routing false 运行的,也就是 angular cli 提供的模板文件。这里 app 就是一个组件,其中包含了 5 个文件。

其中最重要的两个核心文件为 ___.component.ts___.module.ts,而对大多数的组件来说,最核心的是前者的实现,大部分的 ___.module.ts 可能并不太会主动去修改。

下面也会解释为什么 csshtml 并不一定是核心文件的原因

css

当前 CSS 文件是空的:

cat src/app/app.component.css

目前的实现来说,每个 component 中都可以有对应的 CSS 文件,这个对应的 CSS 文件的 作用域(scope) 是当前的组件。

如添加了一个 .header 的 CSS:

.header {background-color: #f2f2f2;padding: 20px;text-align: center;
}

页面上的显示则是:

在这里插入图片描述

可以看到,样式并不是直接作用于 .header 上,而是作用于 .header[_ngcontent-ng-c317606715],后者则是随机生成的 Angular 元素的 属性(attribute,目前观测来看,同一个组件都会分享同一个),这样可以有效防止命名冲突的问题

这个 CSS 文件是通过 @Component 这个 decorator 导入的,使用的属性为 styleUrls,接受的参数是一个数组:

@Component({styleUrls: ['./my-component.component.css']
})

在要写的 CSS 比较多的情况下,一般是会创建一个单独的 ___.component.css 文件,但是在 CSS 样式比较短的情况下,则可以省略文件,直接在 decorator 中添加 styles 即可,如:

@Component({styles: [`h1 {color: blue;}button {background-color: green;color: white;}`]
})

之前看的教程说 stylesstyleUrls 二者只能存在一个,不过现在试了一下,如果二者不冲突的话是都会接受的,而且当前组件如果没有 CSS 的需求,也可以不用放 CSS。

html

这是对应组件的 HTML template,内容如下:

<div style="text-align: center"><h1 class="header">Welcome to {{ title }}!</h1><imgwidth="300"alt="Angular Logo"src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="/>
</div>
<h2>Here are some links to help you start:</h2>
<ul><li><h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2></li><li><h2><a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a></h2></li><li><h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2></li>
</ul>

其本身存在的意义就是生成一个对应的 HTML 模板,通过 module 导入到对应的 HTML   元素中。以目前的例子来说,这个 HTML 模板就是重置 index.html 中的 app-root 元素

每个模板也可以通过 Angular 提供的其他指令与数据的处理层进行交互,并完成数据的动态渲染,这一趴可以理解成传统的 View

一般 HTML Template 通过 @Component 中的 templateUrl进行导入:

@Component({templateUrl: './my-component.component.html'
})

在创建的 HTML 元素比较少的情况下,也不需要单独创建一个 HTML 模板文件,而是使用 template 创建对应的元素即可:

@Component({template: `<div><h1>Hello, {{ name }}!</h1></div>`
})

⚠️:尽管和 CSS 文件一样可以用两种方式进行创建,但是每个 @Component 必须要有一个 templatetemplateUrl。之前看的教程说templatetemplateUrl 只能二选一,我试着跑了一下,目前的版本是会优先选择 templateUrl 中的内容,而不会报错

spec

测试文件,目前不打算涉及,因此跳过

ts

这个可以理解成 ViewModel 层,它主要的作用就是:

  • 创建一个组件类

  • 处理元数据(metadata)

    这个 metada 指的是创建组件所需要的元数据,也就是 @Component 这个装饰器所需要的数据

  • 处理逻辑

    即处理 HTML Template 中需要渲染的数据,并直接与其交互

一个案例代码为:

import { Component } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css'],
})
export class AppComponent {title = 'Hello World';constructor() {}sayHello() {alert(this.title);}
}

这里的 @Component 是一个 TS decorator,说白了也是一个语法糖,大致的极简实现如下:

class Component {constructor(config) {this.selector = config.selector;this.template = config.template;this.render();}// 这样就不需要重复实现这个功能了render() {console.log(`${this.template} is mounted to ${this.selector}`);}
}class SomeComponent extends Component {constructor(config) {super(config);}
}const myComponent = new SomeComponent({selector: 'my-component',template: '<h1>Hello, world!</h1>',
});

这样的调用为:

node ang.js
<h1>Hello, world!</h1> is mounted to my-component

我试了一下 TS 的实现:

type ComponentProps = {selector: string;template: string;
};function Component(config: ComponentProps) {return function <T extends new (...args: any[]) => any>(constructor: T) {return class extends constructor {selector = config.selector;template = config.template;constructor(...args: any[]) {super(...args);this.render();}render() {console.log(`${this.template} is mounted to ${this.selector}`);}};};
}@Component({selector: 'app-server',template: './server.component.html',
})
class ServerComponent {}const serverComponent = new ServerComponent();

不过 TS Playground 上有显示报错就是了,不知道不在 TS Playground 能不能跑起来

module

这个文件用来处理当前组件与其他组件的交互,并最终返回一个 NgModule 供其他的模块使用

一个案例代码为:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';import { AppComponent } from './app.component';@NgModule({// Angular 只会渲染 bootstrap 中包含的组件declarations: [AppComponent],// 这里负责导入本模块中 components 要用的模块// 如与表单交互的 FormsModuleimports: [BrowserModule],// service,现在暂时用不到,用到了再补providers: [],// 这里是导出的组件// React 中只能导出一个组件,Angular 则是一个数组bootstrap: [AppComponent],
})
export class AppModule {}

⚠️:main.ts 中使用的就是这个 AppModule

我个人的理解就是,以乐高作对比,component就像一个个乐高积木,拼成功的一个完成品(比如说 🚗、🌲、🏠 这种)就是一个 NgModuleNgModule 又可以组成更大的 NgModule,比如说乐高的城市主题就会包括消防车、飞机、警局等模块。

因此,对于大多数项目——也就是中小型项目来说,一个应用里面存在一个 app.module.ts 就足够了

新建组件

创建组件有两种方式:使用 angular-cli 和 手动创建

手动创建
  1. 手动创建一个新的文件夹包含 __component.html__.component.ts 即可

    结构如下:

    ❯ tree src/app/
    src/app/
    ├── app.component.css
    ├── app.component.html
    ├── app.component.spec.ts
    ├── app.component.ts
    ├── app.module.ts
    └── serverï├── server.component.html└── server.component.ts
    

    server 下面的就是新的组件,一般命名规范就是这样的

    其中 server.component.html 的内容为对应实现的模板:

    <h1>Hello from Server</h1>
    

    server.component.ts 将对应的 HTML Template 挂载到对应的 div 上——这里在这之前需要在 app.component.html 中创建对应的 HTML 元素,即 <app-server></app-server>server.component.ts 中的代码如下:

    import { Component } from '@angular/core';@Component({selector: 'app-server',templateUrl: './server.component.html',
    })
    export class ServerComponent {}
    
  2. 更新 App.module.ts 中的 declarations

    前文提过,Angular 只会使用 declarations 中提到的组件,因此不更新 declarations,无法正确渲染:

    // 导入,让 TS 可以找到 entry
    import { ServerComponent } from './server/server.component';@NgModule({// 提供信息给 Angulardeclarations: [AppComponent, ServerComponent],// ...其余不变...
    })
    

这个时候 server.component.tsserver.component.html 中的内容就可以正确渲染了:

在这里插入图片描述

使用 cli

这里使用指令即可:

# generate 和 component 分别可以使用 g 和 c 来代替
# component 为 cli 支持创建的类型,除此之外还有 directive、service、class 等
# servers 为对应组件的名称,想要修改也可以用 folder/component 这样的结构
❯ ng generate component servers
CREATE src/app/servers/servers.component.css (0 bytes)
CREATE src/app/servers/servers.component.html (22 bytes)
CREATE src/app/servers/servers.component.spec.ts (608 bytes)
CREATE src/app/servers/servers.component.ts (203 bytes)
UPDATE src/app/app.module.ts (458 bytes)

此时的项目结构为主:

❯ tree src/app/
src/app/
├── app.component.css
├── app.component.html
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── server
│   ├── server.component.html
│   └── server.component.ts
└── servers├── servers.component.css├── servers.component.html├── servers.component.spec.ts└── servers.component.ts3 directories, 11 files

正常情况下,使用 cli 创建的组件会在对应的 module 中被自动添加到 declarations 中去

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Aigtek超声功率放大器的作用是什么

超声功率放大器是一种用于放大超声信号的设备&#xff0c;其作用是增强超声信号的功率&#xff0c;使其能够在超声应用中达到所需的强度和能量。下面西安安泰将详细解释超声功率放大器的作用以及其在不同领域的应用。 超声技术是通过利用超声波的高频振动传递和检测能量&#x…

springboot在线问诊系统-计算机毕业设计源码00211

摘 要 针对医院门诊等问题&#xff0c;对在线问诊进行研究分析&#xff0c;然后开发设计出在线问诊系统以解决问题。在线问诊系统主要功能模块包括首页、轮播图管理、公告信息管理、资源管理、系统用户管理&#xff08;管理员、患者用户、医生用户&#xff09;、模块管理&#…

MongoDB从入门到实战之MongoDB快速入门

前言 上一章节主要概述了MongoDB的优劣势、应用场景和发展史。这一章节将快速的概述一下MongoDB的基本概念&#xff0c;带领大家快速入门MongoDB这个文档型的NoSQL数据库。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战之MongoDB简介&#x1f449; MongoDB从入门到实战…

go_view同后端集成时的注意事项

goview是一个不错的可视化大屏配置工具;提供了丰富的功能可供调用。 官方地址和文档: https://gitee.com/dromara/go-view https://www.mtruning.club/guide/start/ 同nodejs集成可参考;https://gitee.com/qwdingyu/led (建议–后端集成有api功能,可直接配置sql)同dotne…

力扣面试题 17.11. 单词距离(双指针)

Problem: 面试题 17.11. 单词距离 文章目录 题目描述思路复杂度Code 题目描述 思路 Problem力扣面试题 16.06. 最小差 该题目只需预先做一些处理&#xff0c;即可以转换为上述题目&#xff1a; 1.预处理操作&#xff1a;定义两个数组w1ps&#xff0c;w2ps用于记录在words数组中…

【ARM Coresight 系列文章 8.1 - ARM Coresight 通过 APBIC arbiter】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 APBIC arbiter仲裁使用举例APBIC arbiter 在 SoC-600中,APBIC 是用来为 APB4 master 和 APB4 slave 提供 连接关系的组件。APB 是一种简单的总线协议,通常用于低带宽或低性能外设,如定时器、接口控制等。APBIC …

查找二叉树结点C++,数组模拟二叉树

已知一棵二叉树用邻接表结构存储&#xff0c;中序查找二叉树中权值为 x 的结点&#xff0c;并指出该结点在中序遍历中的排列位置。 例&#xff1a;如图二叉树的数据文件的数据格式如下: 输入格式 第一行包含整数 n&#xff0c;表示二叉树的结点数&#xff0c;结点编号从 1 到…

Arduino控制器使用Udp网络对8路IO输出控制

一、实现功能 1、创建串口连接&#xff0c;将接收的Udp数据通过串口发送出去。 2、创建Udp连接&#xff0c;用以接收Udp数据和对发送数据的Udp机器反馈Udp数据 3、对接收到的Udp数据进行解析&#xff0c;然后对8路IO进行输出控制。 4、1对应IO输出低电平&#xff0c;‘0’对…

stack_queue:三个关键注意事项解析

一、stack与容器 template<class T, class Container> class stack { private:Container _con; };Container 为容器&#xff0c;在实例化创建对象时&#xff0c;我们可以传 vector<T> 或 list<T> 等作为栈的底层。 举例&#xff1a; int main() {stack<i…

DES加密解密算法(简单、易懂、超级详细)

目录 一、基础补充 二、什么是DES算法 &#xff08;1&#xff09;对称加密算法 &#xff08;2&#xff09;非对称加密算法 &#xff08;3&#xff09;对称加密算法的应用 三、DES算法的基础操作步骤 1.明文的加密整体过程 2.F轮函数解析 3.密钥的形成过程 四、AC代码 五、D…

代码随想录算法训练营29期Day41|LeetCode 343,96

文档讲解&#xff1a;整数拆分 不同的二叉搜索树 343.整数拆分 题目链接&#xff1a;https://leetcode.cn/problems/integer-break/description/ 思路&#xff1a; 题目要求我们拆分n&#xff0c;拆成k个数使其乘积和最大&#xff0c;然而题目中并没有给出k&#xff0c;所以…

【Mysql】事务的隔离级别与 MVCC

事务隔离级别 我们知道 MySQL 是一个 C/S 架构的服务&#xff0c;对于同一个服务器来说&#xff0c;可以有多个客户端与之连接&#xff0c;每个客户端与服务器连接上之后&#xff0c;就是一个会话&#xff08; Session &#xff09;。每个客户端都可以在自己的会话中向服务器发…

如何使用VSCode上运行Jupyter,详细案例过程出可视化图

Python作为最受AI喜欢的语言之一&#xff0c;我们与大家共同学习下如何在VS Code上运行Jupyter&#xff0c;并且用简单案例实现出图。 环境 VS Code version: 1.80.1 Python: 3.12.0 小白安装过程&#xff1a; 在准备好基础环境&#xff0c;小白心想&#xff0c;AI可是霸占科…

Loadbalancer如何优雅分担服务负荷

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Loadbalancer如何优雅分担服务负荷 前言Loadbalancer基础&#xff1a;数字世界的分配大师1. 分发请求&#xff1a;2. 健康检查&#xff1a;3. 会话保持&#xff1a;4. 可伸缩性&#xff1a;5. 负载均衡…

el-table点击某一行选中改变背景色且执行方法

elementUI table表格点击某一行选中并且改变背景色 使用:row-style"rowStyle"及row-click“selectRow”&#xff1a; 其中 selectRow 方法中&#xff1a; row 输出&#xff1a;当前行的内容 column 输出&#xff1a;当前列的信息 event 输出&#xff1a;当前事件 …

小程序支付类型接入京东支付

一、情景描述 当前项目想在微信小程序付款时添加上京东支付支付类型&#xff0c;效果如下 普通的付款方式可以直接付款就能完成支付&#xff0c;但京东支付无法在小程序上直接付款&#xff0c;他需要复制生成的链接&#xff0c;然后打开京东app然后在京东平台上付款。 所以&…

手机云控制发电机组 有网络随时随地操控监控运行

GenCloudTM 发电机组云控系统简介 Ver2.0 目录 公司简介…… …………………………… ………………………………………………1概 述…… …………………………… ………………………………………………1主要功能及特点………… …………… ………… ………………………………

Mac基于VMware安装CentOS

流程偏长&#xff0c;下一步根本点不完&#xff1b; 01 首先&#xff0c;明确下两款软件的版本信息&#xff1b; VMware是【VMware-Fusion-13.5.0】CentOS是【CentOS-7-x86_64-Minimal-1908】&#xff1b; VMware用来管理虚拟机系统&#xff0c;安装就不多说了&#xff0c;双…

【c语言】深入理解指针(2)

1. 字符指针变量 可以利用字符指针存放字符数组来间接存放字符串。 int main() {char arr[10] "abcdef";char* p arr;printf("p %s\n", p);return 0; } 那我们可不可以直接给字符指针存放字符串呢&#xff1f; int main() {char* p1 "abcde…

51单片机学习笔记 --步进电机驱动说明

文章目录 工作原理代码编写驱动方式全步进驱动半步进驱动微步进驱动 工作原理 工作原理简要说明&#xff0c;和单片机一起配合使用的步进电机多为28BYJ28 五线四相步进电机&#xff0c;配合ULN2003驱动板进行控制&#xff0c;如图所示&#xff0c;对于扭矩、精度要求较高的还有…