一。初识Angular

Angular的开发模型更接近于传统强类型语言的模式,加上官方内建的组件和类库比较完整,学习曲线要低一些。

Posted by Azr on December 29, 2018

Angular 是一个开发平台。它能帮你更轻松的构建Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。

Angular了解

基础知识

  • Augular CLI
  • 模块
  • 组件
  • 模板
  • 数据绑定
  • 服务
  • 路由
  • HttpClient(基于RxJS响应编程)

优点

  1. 由于Google的目的是推出一个完整解决方案,所以官方默认提供的类库(比如routing,http,依赖性注入(DI)等)非常完整,无需自己选择。React的一大痛点就是选择太多导致在配置寻找组件和类库的过程中消耗太多精力,当然从另一方面看这也是其优势,选择众多且自由。
  2. 官方支持TypeScript(微软出品,是JavaScript的超集,是 JavaScript 的强类型版本)作为首选编程语言,使得开发脚本语言的一些问题可以更早更方便的找到。
  3. RxJS友好使得响应式编程在Augular2中变得极为容易(Google开发的框架依赖这么多的微软的产品,可见微软的转型还是很成功的)
  4. 支持NativeScript甚至ReactNative等进行原生Android/iOS应用开发(React支持React Native)
  5. 支持服务器端渲染(React也支持)

Angular CLI

安装

$ npm i -g @angular/cli

输入ng -v进行检查,控制台显示以下内容。

$~ ng -v

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 6.2.2
Node: 8.12.0
OS: darwin x64
Angular: 
... 

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.8.2
@angular-devkit/core         0.8.2
@angular-devkit/schematics   0.8.2
@schematics/angular          0.8.2
@schematics/update           0.8.2
rxjs                         6.2.2
typescript                   2.9.2

创建项目

$ ng new my-app

启动项目

$cd my-app
$ng serve --open

浏览器会自动打开http://localhost:4200/

项目目录结构

.
├── e2e                 端到端测试目录
├── src                 源文件(开发目录)
├── .editorconfig       编辑器统一风格工具配置文件
├── .gitignore          git忽略文件
├── angular.json        Angular CLI 脚手架配置
├── README.md           说明文件
├── package.json        npm配置文件
├── tsconfig.json       TypeScript编译器配置
└── tslint.json         TypeScript语法检查器配置

.
├── src
│   ├── app                 项目源文件( 重点 )
│   ├── assets              存放图片等资源文件
│   ├── browserslist        浏览器支持列表
│   ├── environments        运行环境配置:开发 or 生产
│   ├── favicon.ico         出现在浏览器标签上的应用图标。
│   ├── index.html          项目首页
│   ├── karma.conf.js       karma 测试运行器的配置
│   ├── main.ts             项目入口
│   ├── polyfills.ts        导入JS,兼容老版本浏览器
│   ├── styles.css          全局样式
│   ├── test.ts             测试入口
│   ├── tsconfig.app.json   TypeScript编译器配置
│   ├── tsconfig.spec.json  单元测试文件
│   └── tslint.json         额外的 TypeScript 语法检查器配置

.
├── app
│   ├── app.component.css       app组件样式
│   ├── app.component.html      app组件模板
│   ├── app.component.spec.css  app组件单元测试
│   ├── app.component.ts        app组件JS(TS)代码
│   ├── app.module.ts           根模块

TSlint 的配置

  1. 目的:修改为自己的代码风格

  2. 使用:

    • /tslint.json 中找到要修改的配置文件

    • 将其添加到 src/tslint.json 文件中(或者直接在 /tslint.json 中修改)

模块

  1. 每个应用至少有一个 Angular 模块,称为根模块,它通常命名为 AppModule。根模块的作用:启动应用。

  2. 模块是独立、封闭的。

  3. 模块之间的引用通过导入和导出来完成。

    模块之间的导入导出

  4. 模块中包含的内容

    • 组件
    • 服务
    • 指令

    注意:这些内容必须在模块中配置后才有效

  5. 组件的组成部分

    • 1 [组件名称].component.html
    • 2 [组件名称].component.css
    • 3 [组件名称].component.ts
    • 单元测试文件(可选)[组件名称].component.spec.ts

装饰器

了解

  1. 装饰器是一个函数,又叫做注解。

  2. 作用:修饰紧随其后的类或属性。

  3. 装饰器是 JS 的一种语言特性,处于语法提案的stage2阶段,是一个试验特性。

Angular中装饰器

@NgModule装饰器

  1. @NgModule是Angular提供的装饰器。

  2. 用来告诉Angular将这个类当作模块来处理。

  3. 语法:

     @NgModule({ 
        
         元数据对象 
      })
    
  4. @NgModule装饰器的元数据对象。

序号 元数据对象 解释
1 declarations 该模块所拥有的组件
2 imports 该模块依赖的模块 e.g. BrowserModule
3 providers 该模块所拥有的服务提供商
4 bootstrap 指定根组件,只有根模块需要该配置项Angular 创建它并插入 index.html 宿主页面。
5 exports 公开该模块其中的一部分,以便外部模块使用它们

@Component装饰器

序号 元数据对象 解释
1 selector 选择器(组件名称),对应HTML中的组件名称
2 template 组件的内联模板e.g. template: ‘<div>template</div>’
3 templateUrl 组件模板文件的url,一般使用此项,很少使用template
4 styleUrls 组件样式文件数组
  1. 一般selector的命名是以app- 为前缀

数据绑定

插值表达式



  1. 数据

app.component.html

<h1>Html </h1>
<h2></h2>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // 数据
  title = 'Test';
  data = '2018-12-29';
}

  1. JS表达式

app.component.html

<h1></h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // JS表达式
  a = 1;
  b = 2;
}

  1. 方法中返回的内容

app.component.html

<h1></h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // 方法
  fn() {
    return 'This is fn'
  }
}
  1. 元素的属性绑定

app.component.html

<h1 title=""></h1>

属性绑定

[href]=”属性绑定”


app.component.html

<a [href]="url">皮卡丘~</a>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  url = 'https://ws2.sinaimg.cn/large/006tNbRwly1fyml0ezzwtj30jg0jgq3o.jpg'
}

事件绑定

(click)=”事件绑定 ”


简单的事件绑定

app.component.html

<button (click)=“handleClick()” (mouseenter)=“hamdleMouseenter()”>点我啊</button>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  handleClick() {
    console.log('click')
  }
  hamdleMouseenter() {
    console.log('Mouseenter')
  }
}

事件对象

app.component.html

<a [href]="url" (click)="handleClick()">百度~</a>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
   handleClick() {
    console.log('click')
  };
}

点击页面会触发浏览器的默认行为,进行跳转。

app.component.html

<a [href]="url" (click)="handleClick($event)">百度aaaaaa</a>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
   handleClick(e) {
    // 阻止浏览器的默认行为
    e.preventDefault()
    console.log('事件触发了', e)
  }
}

控制台会打印以下事件对象。

事件触发了 MouseEvent {isTrusted: true, screenX: -1786, screenY: 629, clientX: 57, clientY: 421, …}

双向数据绑定

[(ngModel)]=”双向数据绑定”

双向数据绑定

数据和试图直接形成相互的影响。数据改变,视图就会改变;视图改变,数据就会改变。

从语法看起来像是属性和事件的结合体。


app.component.html

<input type="text" [(ngModel)]="msg">
// 查看元素是否是双向改变
<h1></h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
   msg = "Test"
}

会报错

compiler.js:1021 Uncaught Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("
<br>
<br>
<input type="text" [ERROR ->][(ngModel)]="msg">
"): ng:///AppModule/AppComponent.html@16:19
    at syntaxError (compiler.js:1021)
    at TemplateParser.push../node_modules/@angular/compiler/fesm5/compiler.js.TemplateParser.parse (compiler.js:14830)
    at JitCompiler.push../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._parseTemplate (compiler.js:24018)
    at JitCompiler.push../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._compileTemplate (compiler.js:24005)
    at compiler.js:23948
    at Set.forEach (<anonymous>)
    at JitCompiler.push../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._compileComponents (compiler.js:23948)
    at compiler.js:23858
    at Object.then (compiler.js:1012)
    at JitCompiler.push../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._compileModuleAndComponents (compiler.js:23857)

需要导入模块,才可以使用。用inport导入模块,用@NgModule中的imports导出模块。

app.module.ts

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

//  导入模块
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  // 导出模块
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular语言服务

  1. Link
  2. 自动完成
  3. 错误检查
  4. 给出提示
  5. 内部导航
  6. 安装
    1. VSCode 安装 Angular Language Service
    2. webstorm 在看法模式下安装 ` @angular/language-service@6.0.0`

指令

指令是自定义标签,给现有的HTML标签添加特殊的标记。

指令分类

序号 指令 解释
1 组件 拥有模板的指令
2 属性型指令 改变元素外观和行为的指令
3 结构型指令 添加和移除 DOM 元素改变 DOM 布局的指令

属性型指令

[ngClass] 动态添加或移除CSS类

多个CSS类

app.component.html

<h1 [ngClass]='classList'>ngClass</h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  classList = {
    redColor : true,
    fz: true
  }
}

app.component.css

.redColor {
  background-color: red;
}
.fz {
  font-size: 16px;
}

更改app.component.ts中的classList中的true/false可以看到页面元素class的改变。

单个CSS类

app.component.html

 <p [class.text]="isTest">添加/移除一个类</p>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  isTest = true;
}

app.component.ts文件中isTesttrue,则P标签中有test的类,如果是false,则没有test这个类。

  1. 多个类是对象,只操作一个类是一个布尔值。
  2. 多个使用[ngClass] ,单个使用[class.text]。

[ngStyle] 动态设置内联样式

多个style

app.component.html

<p [ngStyle]="styleList">绿色,50px</p>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  styleList = {
    color: 'green',
    fontSize: '50px'
  }
}
单个style

app.component.html

<p [style.color]="col">黄色</p>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    col = 'yellow'
}

结构型指令

*ngIf 控制元素的展示和隐藏

app.component.html

<h1 *ngIf="isShow">展示出来</h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    isShow = true
}

赋值给isShow的表达式的值是false,那对应的元素将会从DOM中移除,否则生成一个新的元素插入DOM中。

app.component.html

<h1 [class.hidden]="isHidden">隐藏一下</h1>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    isHidden = true
}
  • ngIf是根据表达式的值在DOM元素生成或移除一个元素。比较消耗性能。
  • 频繁的切换展示一般是用CSS的方式。

*ngFor 重复器,遍历数据,批量生成元素

app.component.html

<p *ngFor="let item of nums"></p>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    nums = [1,2,3,4,5,6,6]
}

隔行变色

app.component.html

 <p *ngFor="let item of colors; let i = index; let odd = odd" [class.red]="!odd">  </p>

app.component.ts

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // 数据
  colors = ['red', 'green', 'blue', 'pink']
}

*ngFor添加trackBy

  1. 目的:提升渲染对象数组的性能
  2. 语法:trachBy: trackBy方法名称
  3. 只有在渲染对象数组才有性能的问题,普通的数组是OK的。

app.component.html

<div>
  <!-- 给 ngFor 指令添加 trackBy 提升渲染性能 -->

  <!-- <p *ngFor="let item of colors; trackBy: trackById"></p>
  <button (click)="fetchColors()">重新获取数据</button> -->

  <!-- 演示普通数据有没有性能问题 -->
  <button (click)="fetchData()">重新获取数据</button>
  <ul>
    <li *ngFor="let item of colors"></li>
  </ul>
</div>

app.component.ts

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // 数据
  colors = ['red', 'green', 'blue', 'pink']

  fetchData() {
    setTimeout(() => {
      this.colors = ['red', 'green', 'blue666', 'pink']
    }, 500)
  }

  /* colors = [
    { id: 1, name: 'red' },
    { id: 2, name: 'green' },
    { id: 3, name: 'blue' }
  ]

  fetchColors() {
    setTimeout(() => {
      this.colors = [
        { id: 1, name: 'red' },
        { id: 2, name: 'green 666' },
        { id: 3, name: 'blue' }
      ]
    }, 500)
  }

  trackById(index, color) {
    return color.id
  } */
}

本文首次发布于 Azr的博客, 作者 @azrrrrr ,转载请保留原文链接.

原文链接: http://amor9.cn/2018/12/29/ng1/