找到配置文件:Angular.json
"index": "src/index.html",
"main": "src/main.ts",
程序层面,看main.ts main.ts文件
bootstrapModule(AppModule)
Angular
|
root module : 根模块 bootstrap:(AppComponent)
|
root component : 根组件 (AppComponent)
必然有一个类似 index.html
<app-root> </app-root> 一个标签(元素)就是一个组件
@Component({ selector: 'app-root', 相当于 html 标签 templateUrl: './app.component.html', HTML 文件 styleUrls: ['./app.component.css'] CSS 文件 })
export class AppComponent { //export 可供其他组件调用 title = 'myapp'; //class的属性,与对应的 HTML 文件绑定 }
{{ value }} // Interception 插值,数据绑定 // 称之为:模版变量 (template value)
做个类比: MVC:Component Class 是 控制器(Controller),而 HTML template 就是 View(视图)
component 的 HTML 中, 不要用的标签: <script>
查看 angular.json 文件: "prefix": "app",
在所创建的 component 的 selector 添加了 app selector: 'app-home',
修改 2 个地方 1. app.module.ts 中修改 boostrap 修改为 2. 修改 index.html 入口 为
数据流向:从controller - > template 通过 {{ 变量名称 }},称之为:插补值(intorplation) 注意事项:一定要注意控制器的变量与template的变量名称要一致 Typescript 的数据类型,一律小写。比如 string boolean number
应用场景:通过改变 DOM 元素的属性,动态显示/隐藏一个元素 知识点:HTML 属性与 DOM属性的区别 改变 HTML 属性,浏览器需要刷新 改变 DOM 属性,浏览器会自动刷新 HTML 是由 DOM 决定的 实现思路: 通过控制 DOM 元素的 [hidden] 属性 代码优化: 创建一个类,和类的实例 import class (导入所定义类) 小结: 组件属性绑定: (1)这是组件内的属性绑定,不是组件之间的属性绑定 (2)这里的属性,是指 DOM 元素的属性 (3)这属性,也是指: Class 里面所声明的变量(属性变量) (4)对 DOM 属性操作时,DOM 的属性要加上 []
应用场景:点击 DOM 的 Button(出发一个事件 event),用来显示/隐藏一个 DOM 与元素 实现思路: 获取 button 的点击事件(click event) 编写事件处理的方法 代码优化: 1. 在 class 中声明一个方法(method) 2. 在 DOM 的 button 的 click 事件中,调用 class 所声明的方法
小结: 组件内的事件绑定是指: (1)DOM 元素的事件,通常是 button 的 click 事件 (2)事件的名称是固定的,button 事件要用 click (3)必须绑定 DOM 元素所支持的事件(event)
总结:通过这个实例,实现了 [input] 和 [output] 的联动。 [input] 里面的 input 不是关键字,而是 DOM 元素的属性 [output] 里面的 output,也不是关键字,而是 DOM 元素的 事件(event)名称
应用场景: 把 parent 组件的“值”,传给它的 child 组件,并在 child 组件中显示出这个“值” 这个两个组件在同一个页面,也没有经过服务器的请求 注意:以用户体验为中心,这里讲的是:单页面应用,一个页面由多个组件构成,所以组件之间需要数据交互
实现思路: 前置条件:一定要把 child 组件内置于 parent 组件中。也就是说,parent 组件内嵌了 child 组件 体现组件的父子关系
具体做法
- child 组件内的属性绑定
- parent 组件内的属性绑定
- parent 和 child 组件之间的属性绑定
小结: 1. 组件之间的属性绑定,说白了,就是把parent 组件的“值”传给 child组件 2. 先从 child component 做起,在 child 的 class 中声明一个带有@Input 标识符的属性变量 3. parent 组件的 , 这是 [input] 的 input 就是 child 的 @Input属性变量 4. 组件内的属性绑定与之前的实例是一样的
应用场景: parent component 内嵌了一个 child component,child 的 template 有一个 button ,点击这个button, 把 child 的数据传递给 parent component 数据流向: child -> parent 用到的知识点: Output、EventEmitter (事件发射器)
实现思路: 1. 构建 child 的事件绑定 2. 构建 parent 的事件绑定 3. parent 和 child 的关系
实现过程: 为了美化, 引入 bootstrap 到 index.html
知识点: 设计模式中的观察者模式, EventEmitter 是一个实现了观察者模式的对象,它管理一系列的订阅者(subscribe),并向其发布事件的对象
观察者设计模式: 举例来说, server 返回的数据,放在一个地方,只有去取才能拿到 举例场景: 报刊中心(分发中心) | 订阅者(subscribe),订阅者(subscribe) 只有订阅了,才能得到报刊的信息 有的框架在用到观察者模式时,非常明确,有一个 observer center angular 没有明确的 observer, 但是它由明确的 subscribe subscribe 本身是一个方法,用于订阅变化的信息。
注意事项: 这里所说的 Output 是指 child component 的输出 @Input、@Output 都是以 child component 为参考 @Input、@Output 都是定义在 child component 中
这个模式更像是 delegate 模式(委托模式)
child 发起一个 task,但 child 不执行这个事件;那么,谁来执行这个事件呢?或者说,委托谁来处理这个事件呢? Angular 定义,由 parent 来处理这个事件。
特别注意的事项: parent 与 child 的 @Output、@Input 之间的关系是“固定的”,名字必须一致。 parent 中的(output name)的 output name 必须是 child 中所定义的哪个@Output、@Input
补充:回调函数中,参数的命名不重要,单数的位置是唯一的。 如果一个函数的 callback 函数,ke yi jian dan ming m可以简单命名函数的参数为:(cb),cb:call back 的缩写
知识点:$event 是一个特别的变量,它代表 child component 的 EventEmitter 所发射的内容(对象),它代表是一块数据存储区域。
总结: 自顶向下的数据流:简单;而逆向的数据流,有些复杂,必须通过 EventEmitter 实现
没有 node_modules 文件夹,执行 ng serve -o
方法: 在终端进入此工程目录路径下,执行 npm install 安装工程的依赖包 (modules)
注意: 整个 ng 工程,由 package.json 管理,包括 modules 版本
构建一个页面, 由 2 个 component 组成,一个 product list component,一个是 product create component
product list component (parent)
product create component (child)
当添加一个商品后, 创建的商品会自动添加到 商品列表 中
(一)
1. 构建页面, 引入 bootstrap,在 index.html中,引入 bootstrap 的 cdn
2. 构建 parent 组件
3. 创建一个 Product 类 ng g class product
导入类,创建类的对象
import { Product } from "../product"
products : Product[];
4. *ngFor 循环,用在 template
*ngFor = "let obj of products" 语法解读:
p 是我们定义一个对象,用于遍历数组时,拿到数组中的每个对象
参考 TS 中的 for...of 循环的用法
(二)创建 product create 组件 1. form 表单,引入 bootstrap 2. 添加商品的 button,处理 button 的 click 事件 3. 构建数据,创建 Product 对象,并把 Product 对象发送给 parent 组件 4. 导入 EventEmitter 和 Output import { Component, Oninit, Output, EventEmitter } from '@angular/core'; @Output() selected = new EmitEmitter(); : 这里的 < > 遵循一种协议,发射的对象类型是 Product
知识点:双向数据绑定 two-way data bingding [(ngModel)] 的应用, 它是 {}, 外加[] [ ]: 属性绑定 ( ): 事件绑定 (onChanged) 浏览器出现 error 在 console 所示 can't bind to 'ngModel' since it isn't a known property of 'input'. ("bel for="title">商品名称:) 解决方法:在使用 ngModel 时,一定要在 app.module.ts 中导入
当用到 ngModel 时,一定要设置它的 name 属性
ngModel 小结:通过 input 的 ngModel,实现了双向数据绑定,input 数据来自 class,output 事件由 template 触发,实现了数据的编辑页面。
(三)完成组件之间的绑定 在 parent 组件的 template 中,引入 child 组件的 @Output 方法 <app-product-create (selected) = "addProduct($event)">
注意: ( )里面的函数名称来自 child 组件的 @Output 声明 ()= 等号右边是 parent component 所要实现的方法 $event 参数是一个特别的对象,传值用的
待完善: 用到数据时,需要创建一个 serveice,因为 service 是一个单例 (singleton 单例模式)
知识点:用到 *ngFor 时,一定要注意它加到哪个位置,它对所在的元素做循环 这种用法,是对 做循环,有多少个 取决于数组的length
{{ obj.title }} {{ obj.price }}///-------- 工程改造:-------
方法: 定义一个 # 变量名
简单数据类型:string、number、boolean
使用:不用实例化,var1:boolean;var = false;
对象数据类型:数组、对象(objective),数组是一个典型的对象数据类型
使用:必须实例化
products:Product[]; //声明一个类型(是一个类)
new: //才是实例化
初始化一个数组,给数组直接初始化赋值。(相当于类的实例化)
技巧:
code review:代码走查,项目中,不能出现 hardcode(带有业务逻辑的 hard code)
-
创建需要的组件(header、product-list、product-create)
-
构建路由,在 app.module.ts 中 (1)路由配置 (2)imports 到 RouterModule
-
技能:如何导入一个module?要把 module 导入到 app.module.ts imports:[..] 设置路由方式: Hash 带有 # 的路由
-
路由的配置只是解决了 url 的跳转,但没有解决 component 跳转 const routes: Routes = [ {path: 'home', component: HomeComponent}, ]
-
路由占位符:当满足 URL 时, 这个位置自动被对应的 component 所替代。
-
动态路由的实现,不再用 hardcode
-
调试技巧 {{ }} 两个大括号必须成对出现,否则,Angular 无法识别,也无法取代它的变量,当成了普通字符串来处理
-
知识点:依赖注入(DI:Dependency Injection),在 NG 中,依赖注入常用在 constructor 中 constructor(private router: Router) {} 常规**:用到类时,先声明类,再创建类的实例(new) 依赖注入: 用到类(服务)是,直接拿来就用,不用 new,少了一步 常用到 service 调用上。必须放在 constructor 内才可以。
1. 直接在 index.html 中引入 bootstrap CDN
验证模版是否生效的方法:<button class="btn btn-danger"></button>
2. 通过 npm 指令安装 (npm install bootstrap)
3. 引入 bootstrap
(1)在 styles.css(全局样式)
(2)在 angular.json 文件配置
@import “../node_modules/bootstrap/dist/css/bootstrap.min.css”
注意:是@import,且以;结尾
技能:当配置文件(angular.json)发生变化时,需要重新编译
在 angular 工程中,不再通过传统方式下载引用 bootstrap(<script>)
1. 安装 官网指令安装
知识点:app.module.ts 文件中,@NgModule 中的 declarations 和 imports 区别。
declarations: 放入 components(组件)的地方
imports: 放入 module(模块)
验证 Material design 生效的方法,看看按钮是否有变化 material design 按钮
模拟数据来自第三方: https://jsonplaceholder.typicode.com/photos
知识点:如果自己的 chrome 浏览器没有出现这种规整的JSON数据结构,那么,需要安装一个插件(JsonView)
获取后台数据的方法:
- 引入 HttpClientModule 到 app.module.ts
- 在 app.component.ts 中,注入服务,订阅数据变化,并获取网络数据 constructor(private http: HttpClient){}; ngOnInit(){ this.http.get("https://jsonplaceholder.typicode.com/photos") .subscribe(data => { console.log("from sever data=", data); }) }
获取到后台的数据,并展示在 web 页面上。数据来源:https://jsonplaceholder.typicode.com/photos
1. 构建 Angular 工程。
2. 引入(import) HttpClientModule
在 app.module.ts 文件完成(引入了 module)
还要在 component 引入 httpClient(这是一个 service)
3. 通过 observable(可观察对象),获取到 server 的数据;
4. 通过 订阅 (subscribe)这个 Observable,给 component 提供数据
5. 在组件的 html,显示后台的数据,以 card 样式 展示出来。
每一个 product 的数据结构:
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
}
6. 优化:创建一个 service,通过 service 注入,获取到后台数据。
7. service 给组件提供数据
app.component.ts 文件中,看到 class AppComponent implements OnInit //这里的 implement 是一个关键字,“实现” 具体来说,它“实现”一个接口(interface),为什么要实现一个接口(interface)呢? 因为 interface 只是定义了一个格式(规则),还没有实现,所以要实现它。 参考:OnInit 的接口定义,如下: export interface OnInit{}
$ ng g service xx (product)
This project was generated with Angular CLI version 9.1.6.
Run ng serve
for a dev server. Navigate to http://localhost:4200/
. The app will automatically reload if you change any of the source files.
Run ng generate component component-name
to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module
.
Run ng build
to build the project. The build artifacts will be stored in the dist/
directory. Use the --prod
flag for a production build.
Run ng test
to execute the unit tests via Karma.
Run ng e2e
to execute the end-to-end tests via Protractor.
To get more help on the Angular CLI use ng help
or go check out the Angular CLI README.