angular学习笔记 - 知识点

介绍

angularJs是第一版,angular是第二版以后的统称。
angular不兼容angularJs。
HttpClient(基于RxJS响应式编程)
相比于其他框架,更适用于复杂应用。性能高,体积小。


angular学习笔记 - 知识点_第1张图片

初始化

官方文档,快速上手
npm install -g @angular/cli安装脚手架
ng new my-app创建项目
cd my-app切换到项目
ng serve --open启动项目

文件目录结构

angular学习笔记 - 知识点_第2张图片

angular学习笔记 - 知识点_第3张图片
angular学习笔记 - 知识点_第4张图片

tslint配置

tslint.json

组件体验

angular学习笔记 - 知识点_第5张图片

模块

根模块
作用:启动应用


angular学习笔记 - 知识点_第6张图片

模块:独立、封闭的,模块间的引用通过导入和导出来完成
模块包含:组件、服务、指令,这些要配置后才生效

@NgModule

根组件装饰器
告诉angular将这个类当作模块处理
@NgModule{{元数据对象}}

angular学习笔记 - 知识点_第7张图片

@Component

组件装饰器


angular学习笔记 - 知识点_第8张图片

数据绑定

插值表达式

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

@Component({
  selector: 'app-root',
  // templateUrl: './app.component.html',
  template: '
{{title}}--{{company}}--{{1+2}}-- {{fn()}}
', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = '塞纳河后台管理' company = 'snh' fn () { return '方法返回内容' } }

属性绑定
插值表达式中的属性绑定方式,在执行时最终会转换成这种属性绑定

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

@Component({
  selector: 'app-root',
  // templateUrl: './app.component.html',
  template: `
    链接
    
  `,
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  url = 'http://www.baidu.com'
  isChecked = true
}

事件绑定

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

@Component({
  selector: 'app-root',
  // templateUrl: './app.component.html',
  template: `
    
    链接
  `,
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  url = 'http://www.baidu.com'
  handleClick (event) {
    // 阻止浏览器的默认行为
    event.preventDefault()
    console.log('handleClick', event)
  }
  handleMouseEnter () {
    console.log('handleMouseEnter')
  }
}

双向数据绑定
属性绑定和事件绑定的结合

angular学习笔记 - 知识点_第9张图片

app.module.ts
angular学习笔记 - 知识点_第10张图片

app.component.ts

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

@Component({
  selector: 'app-root',
  // templateUrl: './app.component.html',
  template: `
    
    

{{msg}}

`, styleUrls: ['./app.component.scss'] }) export class AppComponent { msg = '我是默认值' }

语言服务

angular学习笔记 - 知识点_第11张图片

指令

组件:拥有模板的指令
属性型指令:改变元素外观和行为的指令
结构型指令:添加和移除DOM元素,改变DOM布局的指令

[ngClass]

angular学习笔记 - 知识点_第12张图片

[ngStyle]

angular学习笔记 - 知识点_第13张图片

*ngIf

angular学习笔记 - 知识点_第14张图片

*ngFor

基本使用


angular学习笔记 - 知识点_第15张图片

隔行变色


angular学习笔记 - 知识点_第16张图片

使用trackBy解决性能问题
普通数据在渲染时没有性能问题,对象数组在渲染时有性能问题。这时需要使用trackBy来解决。

angular学习笔记 - 知识点_第17张图片

todos案例

组件通讯

ng generate component child 生成子组件,并自动完成了相关的配置

父组件传值给子组件


angular学习笔记 - 知识点_第18张图片

angular学习笔记 - 知识点_第19张图片

angular学习笔记 - 知识点_第20张图片

angular学习笔记 - 知识点_第21张图片

子组件传值给父组件


angular学习笔记 - 知识点_第22张图片

子组件创建事件,触发事件,传递参数


angular学习笔记 - 知识点_第23张图片


父组件绑定事件,接收参数
angular学习笔记 - 知识点_第24张图片

angular学习笔记 - 知识点_第25张图片

todos案例分离组件

ng generate module todos 创建todos模块
目标结构如下

angular学习笔记 - 知识点_第26张图片

指定位置,创建三个子组件
ng generate component todos/todo
ng generate component todos/todo-header
ng generate component todos/todo-list

angular学习笔记 - 知识点_第27张图片

在根模块中使用todos模块

angular学习笔记 - 知识点_第28张图片

angular学习笔记 - 知识点_第29张图片

然后将原来写在根模块中的内容,搬到 todos模块中即可。
注意: FormsModule也要搬过去,否则 todos模块中不能使用。

抽离todo-header组件
要用到组件之间的通讯,子传父 - 任务添加

抽离todo-list组件
任务展示、删除、状态切换
要用到组件之间的通讯,父传子 - 拿到todos数据
要用到组件之间的通讯,子传父 - 删除和修改状态时,要修改父组件中的数据,为了保持数据源的单一性

todo父组件 - 提供代办事项的数据

使用TypeScript

angular官方推荐使用ts
增强了项目的可维护性
有利于协作开发

ts语法

  1. 类型注解
let id: number
  1. 接口
// 创建接口
interface Todo {
  id: number,
  name: string,
  done: boolean
}
export class TodoComponent implements OnInit {
  constructor() { }
  // 任务列表
  todos: Todo[] = [
    { id: 1, name: '玩游戏啊', done: true },
    { id: 2, name: '点外卖呀', done: false },
    { id: 3, name: '看bilibili', done: false }
  ]
}
  1. 泛型
  @Output()
  add = new EventEmitter()
  1. 类成员修饰符
  private todoName: string

接口的另一种使用方式


angular学习笔记 - 知识点_第30张图片
angular学习笔记 - 知识点_第31张图片
angular学习笔记 - 知识点_第32张图片

服务

组件:
提供数据绑定的属性和方法

服务:
处理业务逻辑,供组件使用,如从服务器获取数据、验证用户输入等

组件是服务的消费者

服务说明:

  1. @injectable()装饰器来表示一个服务
  2. 服务要注册提供商才能使用
  3. angular通过依赖注入(DI)来位组件提供服务
  4. DI提供要使用的服务即可。不需要手动创建服务实例
  5. 推荐在constructor中提供组件中用到的服务

服务的创建和基本使用

ng generate service todos/todos 生成服务

todos.service.ts中,如下是服务的提供商,必须有@Injectable

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class TodosService {
  constructor() { }
  // 提供方法
  todoTest () {
    console.log('test-TodoService')
  }
}

使用方式,todo.component.ts,这样,当点击添加的时候,即可调用服务

// 导入服务
import { TodosService } from '../todos.service'

export class TodoComponent implements OnInit, OnChanges {

  constructor(private todoService: TodosService) { }
  addTodo(todoName: string) {
    // 演示服务的调用
    this.todoService.todoTest()
  }

  ngOnInit() {
  }
  ngOnChanges() {
  }
}

注册提供商的三种方式

  1. 根级提供商,在所有组件中都可以调用
@Injectable({
  providedIn: 'root'
})
  1. 模块内可用的提供商

todos.service.ts

@Injectable()

todos.module.ts

// 导入服务
import { TodosService } from './todos.service'
@NgModule({
  providers: [
    TodosService
  ]
})
  1. 组件内可用的提供商(其子组件也可以使用,兄弟组件不可使用)

todos.service.ts

@Injectable()

todo.component.ts

// 导入服务
import { TodosService } from './../todos.service';

@Component({
  providers: [TodosService]
})

export class TodoComponent implements OnInit, OnChanges {
  constructor(private todoService: TodosService) { }
  addTodo(todoName: string) {
    // 演示服务的调用
    this.todoService.todoTest()
  }
  ngOnInit() {
  }
  ngOnChanges() {
  }
}

todos案例使用服务修改

把组件中的业务逻辑抽离到服务中

HttpClient

angular是内置的客户端,不是使用第三方的。

  • 作用: 发送http请求
  • 封装了XMLHttpRequest
  • 使用基于可观察(Observable)对象的api
  • 提供了请求和响应拦截器
  • 流式错误处理机制

HttpClient的基本使用

app.module.ts中导入

// 导入HttpClient模块
import {HttpClientModule} from '@angular/common/http'
@NgModule({
  imports: [
    HttpClientModule
  ],
})

app.component.html触发事件

通过HttpClient获取到的数据是:{{name}}

app.component.ts 接口是用的assets中的json文件模拟的

// 导入HttpClient
import { HttpClient } from '@angular/common/http'
export class AppComponent {
  constructor(private http: HttpClient) { }
  name: string
  getData () {
    this.http.get('../assets/todos.json').subscribe((res: any) => {
      console.log(res)
      this.name = res.name
    })
  }
}

添加类型检查后的app.component.ts ,这种写法比较严谨

interface Todo {
  name: string,
  description: string
}
export class AppComponent {
  constructor(private http: HttpClient) { }
  name: string
  getData () {
    this.http.get('../assets/todos.json').subscribe((res: Todo) => {
      console.log(res)
      this.name = res.name
    })
  }
}

获取完整的响应

使用{ observe: 'response' }即可获取完整的响应
类型检查时要使用HttpResponse

// 导入HttpClient
import { HttpClient, HttpResponse } from '@angular/common/http'

export class AppComponent {
  constructor(private http: HttpClient) { }
  name: string
  getData() {
    this.http.get('../assets/todos.json', { observe: 'response' })
    .subscribe((res: HttpResponse) => {
      console.log(res)
      console.log(res.headers.get('content-type'), res.body)
      this.name = res.body.name
    })
  }
}

错误处理

  getData() {
    this.http.get('../assets/todos.json1', { observe: 'response' })
      .subscribe((res: HttpResponse) => {
        console.log(res)
        console.log(res.headers.get('content-type'), res.body)
        this.name = res.body.name
      },
      err => {
        console.log(err)
      }
    )
  }

json-server

json-server官方文档
npm install -g json-server安装包
新建db.json文件,在里面写好json数据

{
  "todos": [
    { "id": 1, "name": "玩游戏啊", "done": true },
    { "id": 2, "name": "点外卖啊", "done": false },
    { "id": 3, "name": "看bilibii", "done": false }
  ]
}

json-server --watch db.json

angular学习笔记 - 知识点_第33张图片

这就是接口的地址

其他请求

接口地址使用的是json-server生成的地址
app.component.html

app.component.ts

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

// 导入HttpClient
import { HttpClient } from '@angular/common/http'

interface Todo {
  name: string,
  description: string
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  constructor(private http: HttpClient) { }
  name: string
  url = 'http://localhost:3000/todos'
  // get
  getData() {
    this.http.get(this.url).subscribe(res => {
      console.log(res)
    })
  }
  // post
  addData() {
    this.http.post(this.url,{
      name: '测试测试',
      done: true
    }).subscribe(res => {
      console.log('post success:', res)
    })
  }
  // del
  delData() {
    this.http.delete(`${this.url}/2`).subscribe(res => {
      console.log('delete success:', res);
    })
  }
  // patch
  updateData() {
    this.http.patch(`${this.url}/3`,{
      name: '黑呀~我是修改后的数据呀~'
    }).subscribe(res => {
      console.log('patch success:', res)
    })
  }
}

todos案例 HttpClient

路由

实现SPA(单页应用程序)的基础设施
URL和组件的对应规则
angular使用HTML5风格(history.pushState)的导航
支持:重定向、路由高亮、通配符路由、路由参数、子路由、路由模块、路由守卫、异步路由

路由的基本使用

路由的基本使用

  1. index.html
  
  1. 导入RouterModule

  2. 配置路由规则appRoutes

  3. 根模块中配置

    angular学习笔记 - 知识点_第34张图片

    forRoot说明:
    路由服务应该是单例的,但在路由懒加载等场景下会造成服务多次注册,所以使用forRoot()方法导入模块,保证项目中只有一个Router服务

  4. 添加路由出口

配置更多路由

新建组件
配置多个路由规则即可

默认路由

  { path: '', redirectTo: '/home', pathMatch: 'full' }

通配符路由

用来匹配没有的路由规则,跳转到404页面

  // 通配符路由,要放在最后面,不然所有的路由都不能正常匹配
  { path: '**', component: PageNotFoundComponent }`

编程式导航

import { Component, OnInit } from '@angular/core';
// 导入路由提供的服务
import { Router } from '@angular/router'
@Component({
  selector: 'app-page-not-found',
  templateUrl: './page-not-found.component.html',
  styleUrls: ['./page-not-found.component.css']
})
export class PageNotFoundComponent implements OnInit {
  // 注入服务
  constructor(private router: Router) { }
  time = 5

  ngOnInit() {
    const timerId = setInterval( () => {
      this.time--
      if (this.time === 0) {
        clearInterval(timerId)
        // 编程式导航
        this.router.navigate(['/home'])
      }
    }, 1000)
  }
}

路由的参数

ng g c car新建模块
配路由规则,:id表示路由参数

  { 
    path: 'car/:id', 
    component: CarComponent 
  },

app.component.html中设置跳转

  

car.component.ts中获取路由参数

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

// 导入路由服务
import { ActivatedRoute } from '@angular/router'

@Component({
  selector: 'app-car',
  templateUrl: './car.component.html',
  styleUrls: ['./car.component.css']
})
export class CarComponent implements OnInit {

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.route.paramMap.subscribe(param => {
      // param中可拿到当前路由跳转的参数
      const id = param.get('id')
      console.log(param, id);
    })
  }
}

子路由

angular学习笔记 - 知识点_第35张图片

新建组件
配置路由规则

  {
    path: 'home',
    component: HomeComponent,
    children: [{
      path: 'home/child',
      component: HomeChildComponent
    }]
  },

给子路由出口, home.component.html

home works! 子路由

路由激活高亮

  
  
  首页
  关于

表单

  • 响应式表单
    很强大,推荐
    模型驱动,数据驱动视图的思想
    同步的数据访问,保证数据和视图是一致的、可预测的
    增强了可测试性,让测试变得简单
    内置表单验证器

  • 模板驱动表单
    数据双向绑定实现
    vue angular.js

响应式表单

响应式表单

  1. 导入响应式表单模块
import { ReactiveFormsModule } from '@angular/forms';
  1. 生成并导入一个新的表单控件
  2. 在模板中注册该控件
  3. 更新用户名和获取用户名方法
  // 获取用户名
  getUserName () {
    console.log(this.username.value)
  }
  // 更新用户名
  setUserName () {
    this.username.setValue('fdd')
  }

表单验证

  • 内置表单验证器
    username.errors中拿值,判断是否通过校验
    username.dirty中拿值,判断是否输入过

用户名为必填项

hasError()中拿到值,判断是否通过校验

ngOnInit () {
    console.log(this.username)
    console.log(this.username.hasError('required'))
  }

多个条件的校验

  password = new FormControl('123', [
    Validators.required,
    Validators.minLength(4)
  ])
  

密码格式不正确

  • 自定义表单验证器
  // 自定义表单验证
  nickname = new FormControl('', [this.nicknameValidate])
  nicknameValidate(control) {

    console.log(control);
    if (/^[a-z]{3,6}$/.test(control.value)) {
      return null
    }
    return { error: true }
  }
  

昵称格式不正确

FormGroup

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

// 导入表单控件
import { FormControl, Validators, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-form-group',
  templateUrl: './form-group.component.html',
  styleUrls: ['./form-group.component.css']
})
export class FormGroupComponent implements OnInit {
  constructor() { }

  loginForm = new FormGroup({
    username: new FormControl('', Validators.required),
    password: new FormControl('123', [
      Validators.required,
      Validators.minLength(4)
    ])
  });
  onSubmit() {
    if (this.loginForm.valid) {
      console.log('submit');
    } else {
      console.log('err');
    }
  }
  ngOnInit() {
    // console.log(this.loginForm)
  }
}

用户名为必填项

密码格式不正确

FormBuilder

生成表单控件的便捷方法
导入、注入

  loginForm = this.fb.group({
    username: ['', Validators.required],
    password: ['123', [
      Validators.required,
      Validators.minLength(4)
    ]]
  });

你可能感兴趣的:(angular学习笔记 - 知识点)