下载APP

Angular笔记

文章目录

环境搭建

  1. 安装Angular-cli脚手架
npm install -g @angular/cli
  1. 创建项目
> ng new angulardemo

# 添加路由?
? Would you like to add Angular routing? (y/N) y

# 选择使用的 css 预编译器
? Which stylesheet format would you like to use? (Use arrow keys)
  CSS 
> SCSS   [ https://sass-lang.com/documentation/syntax#scss                ] 
  Sass   [ https://sass-lang.com/documentation/syntax#the-indented-syntax ] 
  Less   [ http://lesscss.org                                             ] 
  Stylus [ http://stylus-lang.com                                         ] 
  1. 运行
# 运行
ng serve
# 运行并打开
ng serve --open
  1. VS Code代码提示插件
Angular Snippets

项目结构

文件 含义
main.ts 入口文件
styles.scss 全局样式
src/app 组件
src/app/app.module 默认根组件

main.ts -> src/app/app.module -> 渲染默认根组件

创建组件

获取提示信息,查看ng g可以创建的东西

ng g

app/component下创建一个test组件

ng g component component/test


app.module.ts中同时添加了新增的组件信息

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { TestComponent } from './component/test/test.component';

@NgModule({
  declarations: [	// 组件
    AppComponent,
    TestComponent
  ],
  imports: [	// 模块
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],	// 服务
  bootstrap: [AppComponent]	// 默认组件(根组件)
})
export class AppModule { }

test.component.ts可以查看创建的test组件的名字,添加绑定数据等

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

@Component({
  selector: 'app-test',	// 名字
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {

  public title = "hello test";	// 添加的公共 title 数据

  constructor() { }	// 构造函数

  ngOnInit() {	// 生命周期(初始化加载)函数
  }

}

可以在test.component.html引用绑定的数据

{{ title }}

可以在根组件视图引用该组件

<app-test></app-test>

创建服务

  1. 创建
    app/services下创建一个test服务
ng g service services/test


2. 在app.module.ts注册,和组件不同,服务不会自动注册

import { TestService } from './services/test.service'	// 引入

@NgModule({
  declarations: [
    AppComponent,
    TestComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [TestService],	// 注册服务
  bootstrap: [AppComponent]
})
export class AppModule { }
  1. 使用
/* ... */
import { TestService } from '../../services/test.service';	// 引入

export class TestComponent implements OnInit {
  constructor(private test: TestService) {	// 引到构造函数
    test.say();	// 使用服务
    console.log(test.createAuther);
  }
  /* ... */
}
  1. 服务对象内容
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class TestService {
// 自定义内容 ↓

  // 仅当前类
  private serviceName: string = "testService";
  // 当前及其子类
  protected serviceVersion: string = "v1.0.0";
  // 公共
  public createDate: number = 10;
  // 默认(公共)
  createAuther: string = "ZhangSan";

  public say() {
    console.log(this.serviceName + " " + this.serviceVersion);
  }
  
// 自定义内容 ↑
  constructor() { }

}

打包和编译

打包后无法找到资源

修改根目录,修改 /src/index.html

<!-- <base href="/"> -->
<base href="./">

打包方式及区别

先了解一下 JIT 和 AOT:

  1. JIT(Just In Time即时编译)是运行时优化,AOT(Ahead Of Time)是编译时优化。JIT 在运行时由机器自动侦测使用频率高的代码,将其编译为机器代码提高速度;AOT 是提前将所有代码编译为机器代码,机器无需翻译直接执行。
  2. JIT 特点是编译快,体积大,运行相对较慢;AOT 特点是编译慢,体积小,运行相对较快。
  3. JIT 适合调试使用,AOT 适合上线使用。

ng 通常有3种编译模式:

模式 特点
ng build 常规压缩,体积最大
ng build --aot 预编译,体积较小
ng build --prod 预编译,并进一步精简,体积最小

--prod 本身会执行 --aot,所以无需使用 ng build --prod --aot 来打包

生命周期

函数名 备注
constructor 构造函数(非生命周期函数),可以进行简单的局部变量初始化
ngOnChanges (重新)设置数据绑定输入属性时触发,如props发生改变
ngOnInit 初始化,可进行数据请求
ngDoCheck 数据发生改变时触发
ngAfterContentInit 组件投影初始化
ngAfterContentChecked 组件投影内容发生改变时触发
ngAfterViewInit 视图渲染初始化,可进行DOM操作
ngAfterViewChecked 视图内容发生改变时触发
ngOnDestroy 组件销毁前调用

例子1
init仅在初始化时触发一次;
check用来检查(监测)数据/视图的变化;
多函数同时触发时,按上表依上至下顺序执行

public info: string = "aaa";

// 设置间隔1s改变info的值一次
ngOnInit() {
  setInterval(() => {
    this.info = "bbb";
  },1000)
}

// 每次数据发生改变时都会触发
ngDoCheck() {
  console.log("ngDoCheck");
}


// 执行一次
ngAfterContentInit() {
  console.log("ngafterViewInit")
}

// 每次组件投影内容发生改变时都会触发
ngAfterContentChecked() {
  console.log("ngafterViewChecked")
}


// 执行一次
ngAfterViewInit() {
  console.log("ngafterViewInit")
}

// 每次视图内容发生改变时都会触发
ngAfterViewChecked() {
  console.log("ngafterViewChecked")
}

ngDoCheck
ngafterViewInit
ngafterViewChecked
...1s...
ngDoCheck
ngafterViewChecked
...1s...
ngDoCheck
ngafterViewChecked
...

例子2 - ngOnChanges
注意change仅在数值发生改变时触发,check每次修改即使没改变值也触发

// 接收父元素的一个 prop
@Input() title: string;

// 每当父元素那边的 title 绑定数据发生改变时都触发
ngOnChanges() {
  console.log(this.title);
}

// 注意: 子组件这边自己改变不会触发 ngOnChanges
public changeTitle(): void {
  this.title = "bbb";
}

数据渲染

绑定

文本数据绑定:
<p>{{ title }}</p>

属性绑定:
<div [title]="msg">hover to show title</div>

HTML绑定:
<div [innerHTML]="h"></div>

Class,Style绑定:
<div [ngClass]="{'red': true, 'blue': false}"	<!-- 后面跟布尔值 -->
    [ngStyle]="{'border': '1px solid red'}">	<!-- 值什么的都随意,可以是变量或直接'' -->
    hello
</div>

循环

<ul>
    <li *ngFor = "let person of persons; let i = index">
        {{ i }} : {{ person.name }} {{ person.age }}
    </li>
</ul>

vue一样,let i = index <==> :key = "index"

管道符

预定义管道符

名称 示例 结果
日期 public today: Date = new Date(); 2001-01-20 12:12:56
{{ today | date:'yyyy-MM-dd HH:mm:ss' }}
大小写 {{ "hEllO" | lowercase }} hello
{{ "hEllO" | uppercase }} HELLO
数字保留 {{ 123.5678 | number:'5.2-3' }} 00,123.568
(最少整数位数.最少小数位数-最多小数位数)
(不够最小整数位数补0,超过最多小数位数四舍五入,不够最少小数位数补0)
json序列化 {{ {name: 'tom', 'age': 20} | json }} { "name": "tom", "age": 20 }
字符串截取slice {{ "abcdefg" | slice:2:5 }} cde
管道链 {{ "abcdefg" | slice:2:5 | uppercase }} CDE

自定义管道符
暂时跳过

判断

<p *ngIf="flag">true</p>

switch

<ul [ngSwitch]="n">
    <li *ngSwitchCase="1"> 1 </li>
    <li *ngSwitchCase="2"> 2 </li>
    <li *ngSwitchDefault> * </li>
</ul>

必须用类似ul li这种,然后改下样式,可能是为了好看?

事件

触发

方法直接写数据写的那里,调用用(),和vue@一样

<input type="button" (click)="say()" />

$event

<input type="button" (click)="say($event)" />
say(e) { }

双向数据绑定

  1. 引入,在app.module.ts引入FormsModule
/* ... */
import { FormsModule } from '@angular/forms';	// 引入的组件

@NgModule({
  /* ... */
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule	// 引入的组件
  ],
  /* ... */
})

export class AppModule { }
  1. 使用
<input [(ngModel)]="n" />
{{ n }}

DOM操作

  1. html标记
<div #myBox>hello test</div> 
  1. 引入,操作
// ViewChild, ElementRef 为新增对象
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

/* ... */

export class TestComponent implements OnInit {

  // 'myBox' 为 html 标记名,mybox 为自定义变量名
  @ViewChild('myBox') myBox:ElementRef;
  
  /* ... */
  
  ngOnInit(): void { }	// 初始化生命周期函数

  ngAfterViewInit(): void {	// 视图渲染完毕生命周期函数
    let obj = this.myBox.nativeElement;
    // 使用方法同原生 DOM 对象
    obj.style.border = "1px solid red";
    obj.style.fontSize = "30px";
  }
  
}

父子组件通信

父 <–方法-- 子

假设存在header(子)和test(父)两个组件,父组件要调用子组件的方法:

  1. 父组件引用子组件并命名
<app-header #headerApp></app-header>
  1. 调用
import { Component, OnInit, ViewChild } from '@angular/core';

/* ... */

export class TestComponent implements OnInit {

  @ViewChild('headerApp',null) headerApp: any;	// 这里用 any 类型可以防止调用方法时报错
  
  /* ... */

  ngAfterViewInit(): void {
    this.headerApp.say();	// 调用子组件的方法
  }

}

父 --方法–> 子

类似vue$emit

  1. 子组件
import { Component, OnInit, Output, EventEmitter } from '@angular/core';

/* ... */

export class HeaderComponent implements OnInit {

  // 子组件实例化`EventEmitter`
  @Output() private say = new EventEmitter<string>();

  // 调用
  public fatherSay(): void {
    this.say.emit();  // 无参
    this.say.emit("this is a message from header"); // 有参(该方法仅能接收一个字符串参数)
  }

  /* ... */

}
  1. 父组件
<!-- 注意这里有参传过来的话要用 $event 来接收,即使只能传过来一个字符串
<app-header (say)="runSay($event)"></app-header>
// 用 string 接收
public runSay(msg: string): void {
  if(msg){
    console.log(msg);
    return;
  }
  console.log("this is a message from test");
}

父 --数据–> 子

假设存在header(子)和test(父)两个组件

  1. header引用子组件,用[]传值给子组件
<app-header [title]="message"></app-header>
  1. test接收数据
import { Component, OnInit, Input } from '@angular/core';

/* ... */

export class HeaderComponent implements OnInit {

  @Input() title: string;

  constructor() { }

  ngOnInit() {
    console.log(this.title);	// 使用
  }

}
在线举报