Angular學(xué)習(xí)筆記

angular 的優(yōu)點(diǎn)

  • 組織化前端結(jié)構(gòu)
  • 強(qiáng)大和新穎
  • 完整的解決方案(路由、HTTP、RxJS等)
  • 構(gòu)建強(qiáng)大單頁應(yīng)用
  • MVC設(shè)計(jì)模式
  • Tyepscript
  • 極好的cli工具

預(yù)備知識(shí)

  • Typescript
  • Classes
  • 高階函數(shù) - forEach、map、filter
  • 箭頭函數(shù)
  • Promise
  • MVC設(shè)計(jì)模式

the angular way

  • 使用Typescript(變量、函數(shù)、參數(shù))
  • 基于組件component based
  • 使用service來共享組件間的數(shù)據(jù)/功能
  • modules的概念(root module, forms modules, http module, etc)
  • 使用RxJS的observables來異步操作。(使用內(nèi)置的HTTP模塊發(fā)送請求,在組件中訂閱返回的Observables)
  • 較陡的學(xué)習(xí)曲線

angular 基本用法

創(chuàng)建項(xiàng)目

ng new myapp

啟動(dòng)項(xiàng)目

ng serve

打包項(xiàng)目

ng build

創(chuàng)建組件

ng generate component todos

創(chuàng)建服務(wù)

ng generate service todo

創(chuàng)建模塊

ng generate module <moduleName>

在Angular的大型應(yīng)用中可以使用ngrxRedux等狀態(tài)管理工具

項(xiàng)目準(zhǔn)備

安裝angular
sudo npm install -g @angular/cli
驗(yàn)證安裝
ng --version
新建項(xiàng)目
ng new todolist
運(yùn)行項(xiàng)目
ng serve --open

index.html

單頁應(yīng)用入口,可以在這個(gè)文件中引入CDN,<app-root>是組件的根標(biāo)簽

angular.json

項(xiàng)目配置文件,如打包目錄(outputPath),靜態(tài)資源目錄(assets),樣式目錄(styles)

app.module.ts

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular中所有module必須導(dǎo)入后才能使用,如果使用cli創(chuàng)建模塊,會(huì)自動(dòng)進(jìn)行導(dǎo)入

  • imports 使其他模塊的導(dǎo)出聲明在當(dāng)前模塊中可用

  • declarations 使當(dāng)前模塊中的指令(包括組件和管道)可用于當(dāng)前模塊中的其他指令

  • providers依賴注入知道servicesvalue,它們添加到root scope,并且注入到依賴它們的服務(wù)或指令

  • bootstrap數(shù)組聲明哪些組件需要插入到index.html

將多個(gè)組件插入到index.html

index.html

<app-root></app-root>
<test-root></test-root>

test.component.ts

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

@Component({
  selector: "test-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class TestComponent {
  title = "test";
}

app.module.ts

// ...
import { TestComponent } from "./test.component";
@NgModule({
  declarations: [AppComponent, TestComponent],
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent, TestComponent],
})
export class AppModule {}

基礎(chǔ)語法

創(chuàng)建組件
ng generate component components/Todos
ng g c components/TodoItem
// 創(chuàng)建服務(wù)
ng g s services/Todo

該命令會(huì)在components文件夾下創(chuàng)建新的組件

屬性綁定

[屬性名]="屬性值"

app/components/todo-item/todo-item.component.html

<div [ngClass]="setClasses()">
  <p>
    <input
      (change)="onToggle(todo)"
      type="checkbox"
      [checked]="todo.completed"
    />
    {{ todo.title }}
    <button (click)="onDelete(todo)" class="del">x</button>
  </p>
</div>
*ngFor循環(huán)語句

app/components/todos/todos.component.html

<app-todo-item *ngFor="let todo of todos" [todo]="todo"> </app-todo-item>
向子組件傳參

[參數(shù)名]="參數(shù)值"向子組件傳值

app/components/todos/todos.component.html

<app-todo-item *ngFor="let todo of todos" [todo]="todo"> </app-todo-item>

[todo]="todo"app-todo-item組件傳值

接收參數(shù)

app/components/todo-item/todo-item.component.ts

export class TodoItemComponent implements OnInit {
  @Input() todo: Todo;
}

在模板中使用參數(shù)

app/components/todo-item/todo-item.component.html

<div [ngClass]="setClasses()">
  <p>
    <input
      (change)="onToggle(todo)"
      type="checkbox"
      [checked]="todo.completed"
    />
    {{ todo.title }}
    <button (click)="onDelete(todo)" class="del">x</button>
  </p>
</div>
向父組件傳參

app/components/todo-item/todo-item.component.ts

import { Component, OnInit, Input, EventEmitter, Output } from "@angular/core";
import { Todo } from "../../models/Todo";
import { TodoService } from "../../services/todo.service";
@Component({
  selector: "app-todo-item",
  templateUrl: "./todo-item.component.html",
  styleUrls: ["./todo-item.component.css"],
})
export class TodoItemComponent implements OnInit {
  // 從父組件接收參數(shù)
  @Input() todo: Todo;
  // 向父組件傳遞參數(shù)
  @Output() deleteTodo: EventEmitter<Todo> = new EventEmitter();
  constructor(private todoService: TodoService) {}

  ngOnInit(): void {}
  setClasses() {
    let classes = {
      todo: true,
      "is-completed": this.todo.completed,
    };
    return classes;
  }

  // onToggle
  onToggle(todo) {
    // Toggle on UI
    todo.completed = !todo.completed;
    // Toggle on server
    this.todoService.toggleCompleted(todo).subscribe((todo) => {
      console.log(todo);
    });
  }
  // 通過 emit 向父組件傳參
  onDelete(todo) {
    this.deleteTodo.emit(todo);
  }
}

app/components/todos/todos.component.html

<app-todo-item
  *ngFor="let todo of todos"
  [todo]="todo"
  (deleteTodo)="deleteTodo($event)"
>
</app-todo-item>

(deleteTodo)監(jiān)聽這個(gè)事件的名稱和子組件的EventEmitter對象名必須一致

ngClass動(dòng)態(tài)添加類

在HTML元素上添加或者移除CSS類

app/components/todo-item/todo-item.component.html

<div [ngClass]="setClasses()">
  <p>
    <input type="checkbox" />
    <button class="del">x</button>
  </p>
</div>

其中setClasses()是腳本文件中的一個(gè)方法

app/components/todo-item/todo-item.component.ts

export class TodoItemComponent implements OnInit {
  @Input() todo: Todo;
  constructor() {}

  ngOnInit(): void {}
  setClasses() {
    let classes = {
      todo: true,
      "is-completed": this.todo.completed,
    };
    return classes;
  }
}
監(jiān)聽事件

app/components/todo-item/todo-item.component.html

<div [ngClass]="setClasses()">
  <p>
    <input (change)="onToggle(todo)" type="checkbox" />
    {{ todo.title }}
    <button (click)="onDelete(todo)" class="del">x</button>
  </p>
</div>

(change)監(jiān)聽輸入框改變事件,(click)監(jiān)聽元素點(diǎn)擊事件

網(wǎng)絡(luò)請求

導(dǎo)入HTTP請求模塊

app.module.ts

import { HttpClientModule } from "@angular/common/http";
@NgModule({
  declarations: [AppComponent, TodosComponent, TodoItemComponent],
  imports: [BrowserModule, AppRoutingModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

services發(fā)送請求

app/services/todo.service.ts

import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Todo } from "../models/Todo";
import { Observable } from "rxjs";
@Injectable({
  providedIn: "root",
})
export class TodoService {
  todoUrl: string = "https://jsonplaceholder.typicode.com/todos?_limit=5";
  constructor(private http: HttpClient) {}
  getTodos(): Observable<Todo[]> {
    return this.http.get<Todo[]>(this.todoUrl);
  }
}
表單

導(dǎo)入表單模塊

app.module.ts

import { FormsModule } from "@angular/forms";

@NgModule({
  declarations: [
    AppComponent,
    TodosComponent,
    TodoItemComponent,
    HeaderComponent,
    AddTodoComponent,
  ],

  imports: [BrowserModule, AppRoutingModule, HttpClientModule, FormsModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

在表單元素中使用雙向數(shù)據(jù)綁定

app/components/add-todo/add-todo.component.html

<form class="form" (ngSubmit)="onSubmit()">
  <input
    type="text"
    name="title"
    [(ngModel)]="title"
    placeholder="Add Todo..."
  />
  <input type="submit" value="submit" class="btn" />
  {{ title }}
</form>

[(ngModel)]用于雙向數(shù)據(jù)綁定

(ngSubmit)監(jiān)聽表單提交事件

監(jiān)聽表單提交事件

app/components/add-todo/add-todo.component.ts

import { Component, OnInit, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-add-todo",
  templateUrl: "./add-todo.component.html",
  styleUrls: ["./add-todo.component.css"],
})
export class AddTodoComponent implements OnInit {
  title: string;
  @Output() addTodo: EventEmitter<any> = new EventEmitter();

  constructor() {}

  ngOnInit(): void {}
  onSubmit() {
    const todo = {
      title: this.title,
      completed: false,
    };
    // 觸發(fā) addTodo 事件
    this.addTodo.emit(todo);
  }
}

表單提交事件處理

**app/components/todos/todos.component.html **

<app-add-todo (addTodo)="addTodo($event)"></app-add-todo>
<app-todo-item
  *ngFor="let todo of todos"
  [todo]="todo"
  (deleteTodo)="deleteTodo($event)"
>
</app-todo-item>

app/services/todo.service.ts

import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Todo } from "../models/Todo";
import { Observable } from "rxjs";
const httpOptions = {
  headers: new HttpHeaders({
    "Content-Type": "application/json",
  }),
};
@Injectable({
  providedIn: "root",
})
export class TodoService {
  todoUrl: string = "https://jsonplaceholder.typicode.com/todos";
  todoLimit = "?_limit=5";

  constructor(private http: HttpClient) {}
  getTodos(): Observable<Todo[]> {
    return this.http.get<Todo[]>(`${this.todoUrl}${this.todoLimit}`);
  }
  // Toggle Completed
  // 發(fā)送json類型數(shù)據(jù)必須帶請求頭
  toggleCompleted(todo: Todo): Observable<any> {
    const url = `${this.todoUrl}/${todo.id}`;
    return this.http.put(url, todo, httpOptions);
  }
  deleteTodo(todo: Todo): Observable<Todo> {
    const url = `${this.todoUrl}/${todo.id}`;
    return this.http.delete<Todo>(url, httpOptions);
  }
  addTodo(todo: Todo): Observable<Todo> {
    return this.http.post<Todo>(this.todoUrl, todo, httpOptions);
  }
}
路由

app/app-routing.module.ts

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { TodosComponent } from "./components/todos/todos.component";
import { AboutComponent } from "./components/about/about.component";
const routes: Routes = [
  {
    path: "",
    component: TodosComponent,
  },
  {
    path: "about",
    component: AboutComponent,
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

app/app.component.html

<app-header></app-header>
<!-- <app-todos></app-todos> -->
<router-outlet></router-outlet>

路由跳轉(zhuǎn)

app/components/layout/header/header.component.html

<header class="header">
  <h1>TODO</h1>
  <a routerLink="/">Home</a>
  <a routerLink="/about">About</a>
</header>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容