EP10-zake学angular

293 阅读14分钟

内容来源于网络,仅为个人理解记忆方便
参考文档:

1,angular中的HTTP

参考文章:Angular 6 HttpClient 快速入门

1,在模块中引入 HttpClientModule

import { HttpClientModule } from '@angular/common/http'

在angular6中http请求默认返回的是json数据,不需要增加一步转化数据的步骤。

.map(res => res.json()).

2, 在TS文件中导入http服务

import { HttpClient } from '@angular/common/http';
export class myComponent implements OnInits {
	construct(private http: HttpClient){
    }
}

2,模板语法

1,ngIf else

<span *ngIf="isReverse, else peerReverseTunnel" style="text-align: center; display: block; color: red;">请选择正向</span>
//peerReverseTunnel是模板引用变量
<ng-template #peerReverseTunnel> 
    <span style="text-align: center; display: block; color: red;">请选择反向</span>
</ng-template>

2,ng-template , ng-container, ng-content

  • 1, ng-container标签不渲染为DOM,默认显示标签内部内容,一般搭配ngif,ngfor使用。
  • 2, ng-content:父组件调用子组件时,将父组件的内容投射到子组件指定位置,类似于vue中的插槽。分为默认插槽与具名插槽。

//默认投射
//父组件
<app-child-com>
  <p>- parent component content !!! -</p>
</app-child-com>
//子组件
<p>child component content - begin</p>
  //此处放入 p 标签中的内容
  <ng-content></ng-content>
<p>child component content - end</p>



//具名投射
<app-child-com>
  <header>
    header - parent component content !!! -
  </header>
  <div id="demo">
    id selector - parent component content !!! -
  </div>
  <div name="demo">
    name - parent component content !!! -
  </div>
</app-child-com>

<p>child component content</p>
<ng-content select="header"></ng-content>
<p>child component content</p>
<ng-content select="#demo"></ng-content>
<p>child component content</p>
<ng-content select="[name=demo]"></ng-content>

  • 3,ng-template默认不显示。

3,插值

插值中可以使用函数调用,因为函数调用是有返回值的,类似于表达式。

4,模板中的表达式

1,不能使用的JavaScript表达式

不能使用可能导致副作用的JavaScript表达式。

  • 赋值 =,+=,-=
  • new,typeof,instanceof等运算符
  • 使用;或者,串联起来的表达式。
  • 自增和自减运算符。
  • 一些ES6+的运算符。

2,表达式上下文

  • 模板变量 模板输入变量
    模板引用变量
    模板引用变量和模板输入变量不同,模板引用变量的范围是整个模板,不要在同一模板中多次定义相同的变量名。
  • 指令的上下文变量
  • 组件的成员

3,表达式中的运算符

1,管道

angular为典型的数据转换提供了内置的管道,数据格式化常用的管道如下:

  • DatePipe
  • UpperCasePipe
  • LowerCasePipe
  • CurrencyPipe
  • DecimalPipe
  • PercentPipe
2,管道和变更检测

angular会在每次DOM事件(按键,鼠标移动,计时器,服务器响应)之后运行的变更检测过程中查找对数据绑定值的更改。
默认情况下,管道会被定义为纯的,这样angular在检测到输入值发生了纯变更时才会执行该管道。
纯变更是对原始输入值(string,number,boolean,symbol)或者对象引用的变更(date, array, function,object)。
检测对象中的非纯变更,要在对象内部进行更改之后执行自定义管道(例如更改数组元素),就需要把管道定义为impure以检测非纯的变更。每当鼠标移动或者按键时,angular都会检测到一次变更,从而执行一个非纯管道。
虽然非纯管道很实用,但是长时间运行非纯管道会降低应用的性能。
通过把pure标志设置为false来把管道设置为非纯的:

@Pipe({
    name: 'flyingHeroesImpure',
    pure: false
})
2,安全导航运算符

angular安全导航运算符?.可以对在属性路径中出现的null和undefined进行保护,防止视图渲染失败。

<p>The item name is: {{item?.name}}</p>

类似于typescript中的可选链运算符。

3,非空断言运算符
 <!-- Assert color is defined, even if according to the `Item` type it could be undefined. -->
<p>The item's color is: {{item.color!.toUpperCase()}}</p>`

与安全导航运算符不同的是,非空断言运算符不会防止出现null和undefined。只是告诉typescript的类型检查器对特定的属性表达式,不做严格空值检测。
非空断言运算符是可选的。

5,数据绑定

1,property绑定

2,事件绑定

事件绑定允许监听某些事件,例如按键,鼠标移动,点击和触屏。

3,Attribute绑定

<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

attribute绑定的主要用例之一是设置ARIA attribute,ARIA指无障碍功能,用于给残障人士访问互联网提供便利。

4,类绑定

  • 类绑定与属性型指令的区别?
1,单个类绑定

<!--hasFoo为boolean -->
<div [class.foo]="hasFoo"></div>
2,多个类绑定
<!-- classExpr可以是类名分隔的字符串,或者是类名为键,boolean为值的对象-->
<div [class]="classExpr"></div>

5,样式绑定

## 1,单个样式绑定

2,多个样式绑定

6

3, angular中的service

其他

1,service在组件间消息传递上的作用

angular中service在消息传递的作用上类似于Vue的eventBus。
Vue中的eventBus的实现方式:
在需要实现相互通信的兄弟组件中,都引入一个Vue实例,然后通过分别调用这个实例的事件触发和监听来实现通信和参数传递。

2,为什么angular不需要像react那样必须有个状态管理库

参考文档:

因为有service。
还有rxjs。

4, 双向数据绑定

1,什么是双向数据绑定

数据变化更新视图,视图变化更新数据。

  1. view层的数据改变,model层的数据也会跟着发生变化。可以通过浏览器自身的事件响应来实现。
  2. view层响应model层的数据变化。两个方面:一,model层的数据渲染到view层;二,检测到model层的数据发生变化,angular通过脏检查实现,vue2版本是通过getter和setter以及Object.defineProperty(数据劫持)实现的。
    ps:
  3. react没有实现双向数据绑定,需要手动实现。
  4. 事件监听其实是一种观察者模式。

5,angular的生命周期

1,生命周期的种类

  • ngOnChanges() 在ngOnInit()之前以及所绑定的属性发生变化时都会调用。
  • ngOnInit() 只调用一次
  • ngDoCheck() 紧跟在每次变更检测时的ngOnChanges和首次执行变更检测时的ngOnInit()调用。
  • ngAfterContentInit() (组件独有) 当angular把外部内容投影进组件视图或者指令所在的视图之后调用,
    第一次ngDoCheck()之后调用,只调用一次
  • ngAfterContentCheckd() (组件独有) 每当angular检查完投影到组件或者指令中的内容之后调用,
    ngAfterContentInit()和每次ngDoCheck()之后调用。
  • ngAfterViewInit() (组件独有) 当angular初始化完组件视图及其子视图或包含该指令的视图之后调用,
    第一次ngAfterContentChecked()之后调用,只调用一次。
  • ngAfterViewCheckd() (组件独有) ngAfterViewInit()和ngAfterContentChecked()之后调用。
  • ngOnDestroy() angular每次销毁指令或者组件之前调用并清扫。

6,angular脚手架ng的使用

1,新建一个项目

ng new myProject

其他

1,angular引入第三方组件

1,angular引入jQuery

参考文档:angular6---引入jquery

1,第一步,进入项目目录,下载jQuery

npm i jquery -S

2,第二步,下载type文件

npm i @types/jquery -S

执行完上面两步之后,会在项目的package.json文件中的dependencies增加两行

image.png

3,在需要使用jQuery的地方引入

image.png

7,angular的状态管理

状态管理实际上就是利用纯函数维护一个数据对象,以保证数据一致性。 angular状态管理的几种方法:

  • 在组件中维护
  • 在服务中维护
  • 组件中一部分,服务中一部分
  • 使用localstorage存储

1,ngrx/store

github地址:
@ngrx
ngrx其实就相当于ng版本的redux + redux-observable。

2,ngxs/store

Angular 真的需要状态管理么?
GitHub地址:
ngxs/store
使用rxjs管理状态,比ngrx好用,使用装饰器定义state和action,组件通过store.dispatch(new AddTodo('title'))调用对应的action方法,充分利用了angular和typescript的特质。

8,angular国际化

参考文档 :

9,装饰器

1,类装饰器

1,@Component

2, @Directive

3, @Pipe

4, @Injectable

5, @NgModule

2,属性装饰器

1, @Input

2, @Output

3, @HostBinding

4, @HostListener

5, @ContentChild

6, @ContentChildren

7, @ViewChild

8, @ViewChildren

3,参数装饰器

1, @Inject

2, @Optional

3, @Self

4, @SkipSelf

5, @Host

6, @Attribute

10,服务

angular中的服务是封装了某一特定功能,并且可以通过注入的方式供他人使用的独立模块。
angular可以通过查看构造函数的参数类型,来得知组件需要哪些服务。

1,内置服务

2,自定义服务

11,依赖注入

依赖注入是一种重要的设计模式,angular有自己的依赖注入框架。
依赖是当类需要执行其功能时,所需要的服务或者对象。
DI是一种编码模式,其中的类会从外部源中获取请求依赖,而不是自己创建他们。
注入器是可继承的,如果指定的注入器无法解析某个依赖,它就会请求父注入器来解析它。组件可以从自己的注入器中来获取服务,从祖先组件的注入器中获取,从父ngmodule的注入器中获取,或从root注入器中获取。

在某个注入器的范围内,服务是单例的。也就是说在指定的注入器中最多只有某个服务的最多一个实例。

依赖注入令牌 当使用服务提供者配置注入器时,就会把服务提供者和一个DI令牌关联起来。注入器内部维护着一个令牌-服务提供者的映射表,当请求一个依赖项时就会引用它。令牌及时这个映射表的键。

可选依赖 通过给依赖加上@optional注解,可以告诉angular,该依赖是可选的。

import { Optional } from '@angular/core';
constructor(@Optional() private logger?: Logger) {
  if (this.logger) {
    this.logger.log(someMessage);
  }
}

依赖提供者会使用DI令牌来配置注入器,注入器会用他来提供这个依赖值的具体的,运行时版本。
可以使用服务类来配置注入器,也可以提供一个替代类,一个对象,或者一个工厂函数。

angular将providers值拓展为一个完整的提供者对象,

[{ provide: Logger, useClass: Logger }]

第二个属性是提供者定义对象,他告诉注入器如何创建依赖值。提供者定义对象中的key既可以是useclass,useExisting,useValue, useFactory.每一个key都用于提供一种不同类型的依赖。

配置带依赖的类提供者,如果替代类提供者有自己的依赖,那就在父模块或组件的元数据属性providers中指定那些依赖。

[ 
  UserService,
  { provide: Logger, useClass: EvenBetterLogger }
]

别名类提供者,要为类提供者设置别名,需要在providers数组中使用useExisting属性指定别名和类提供程序。

[ NewLogger,
  // Alias OldLogger w/ reference to NewLogger
  { provide: OldLogger, useExisting: NewLogger}]

12,路由

1,路由懒加载

//懒加载路由配置
const routes: Routes = [
  {
    path: "",
    redirectTo: 'login', pathMatch: 'full'
  },
  {
    path: "login",
    //下面这种方式不起作用
    // loadChildren: "./login/login.module#LoginModule"
    loadChildren: ()=>import('./login/login.module').then(mod=>mod.LoginModule)
  }
  
];

13,模块

angular模块是一个带有@NgModule装饰器的类,它接收一个用来描述模块属性的元数据对象。

1,模块元数据

1,declaration(声明)

属于这个模块的视图类。
angular有三种类型的视图类:组件,指令和管道。

2,exports

声明的子集,可以用于其他模块中的组件模板。
angular中如何向模块外提供内部定义的管道和指令\color{red}{angular中如何向模块外提供内部定义的管道和指令}

3,imports

本模块组件模板中需要由其他导出类的模块。

4,providers

服务的创建者。

5,bootstrap

应用的主视图,称为根组件,它是其他应用视图的宿主。只有根模块需要设置bootstrap属性。

2,内置模块

1, BrowserModule

提供了运行在浏览器中的应用所需要的关键服务和指令,这个模块在所有需要在浏览器中跑的应用都需要。

2,FormsModule

提供了表单处理和双向绑定等服务和指令

3,HttpModule

提供了http请求和响应的服务。

14,指令

angular模板是动态的,当angular渲染他们时,会根据指令对DOM进行修改。
指令是带有指令元数据的类。
在angular中,有三种类型的指令:

  1. 属性指令,以元素的属性形式来使用的指令。
  2. 结构指令,用来改变DOM树的结构。
  3. 组件,作为指令的一个重要子类,组件本质上是可以看作一个带有模板的指令。

15,组件

组件是一个模板的控制类,用于处理应用和逻辑页面的视图部分。

1,组件元数据

元数据告诉angular如何处理一个类。

16, angular中的rxjs

1, ngrx/component

RFC: Component: Proposal for a new package component 让angular可以直接充当rxjs的视图层使用。

17,表单

1,表单验证

1,监测input项的状态

使用#变量引用ngmodel,获取其状态。

    <div>
      <input required type="text"
        [(ngModel)]="username"
        #usernameRef="ngModel"
        />
        {{usernameRef.valid}}
      <input required type="password"
        [(ngModel)]="password"
        #passwordRef="ngModel"
        />
        {{passwordRef.valid}}
      <button (click)="onClick()">Login</button>
    </div>

18,样式

1,组件样式

组件样式在很多方面不同于传统的全局性样式。放在组件样式中的选择器,只会用在组件自身的模板中。
这种模块化相对于CSS的传统工作方式的优点:

  • CSS类名和选择器是控件范围的,属于组件内部,不会出现命名冲突。
  • 样式不会因为其他地方的样式修改而意外改变。
  • 将每个组件的typescript,HTML和CSS放在一起,代码结构清晰。
  • 修改组件的样式时,不用担心在其他地方被引用。

1x,变更检测

angular脏检查机制是事件驱动,由zone.js实现。
单向数据流。

1xx,angular2架构

angular2应用程序主要由以下8个部分组成:

  1. 模块(module)

  2. 组件(component)

  3. 模板(template)

  4. 元数据(metadata)

  5. 数据绑定(data binding) 数据绑定为应用程序提供了一种简单而一致的方法来显示数据和数据交互,是管理应用程序里面数值的一种机制。angular中数据绑定有四种语法:插值,属性绑定,时间绑定,双向绑定。

  6. 指令(directives)

  7. 服务(service)

  8. 依赖注入(dependency injection)

image.png

其他

1,angular解决的问题

1,angular解决分工协作的问题

在angular中,使用模块来解决分工协作的问题。
通过模块来隐藏一些不能共用的组件。

2,angular解决契约问题

使用类型与测试来解决契约问题。
angular借助typescript来对类型提供支持。
类型只能对契约进行一定程度的表达,更高层次的契约需要测试来实现。

3,angular解决代码风格问题

1,在angular中增加webpack配置

angular-builders

1,在angular6中增加webpack配置

参靠文档: angular6 增加webpack配置 亲测可用

"@angular-builders/custom-webpack": "^6.0.0",
"@angular-builders/dev-server": "^6.0.0",

必须是上面这两个版本,其他版本可能报错。

2,在angular9中增加webpack配置
  • 安装"@angular-builders/custom-webpack": "^11.1.0"
    使用12.1.0版本报错。
  • 配置angular.json文件 build-> builder:"@angular-builders/custom-webpack:browser"
    build-> options增加:
"customWebpackConfig": {
              "path": "./extra-webpack.config.js",
              "mergeStrategies": {
                  "loaders": "append"
              }
            },

serve -> builder: @angular-builders/custom-webpack:dev-server

  • extra-webpack.config.js文件配置
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    // 开启 BundleAnalyzerPlugin
    //new BundleAnalyzerPlugin(),
  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        
      },
    },
  },
  devServer: {
    publicPath: "/iui/xxxx-xxxx-xxxxx-ui/",
    proxy: [
      {
        context: ["/api", "/iui", "/portal"],
        target: "https://xxxxx:28001", //调试api地址
        changeOrigin: true,
        secure: false,
        //重写cookie
        onProxyRes: function (proxyRes, req, res) {
          const rawCookie = proxyRes.headers["set-cookie"];
          if (rawCookie) {
            let newCookie = rawCookie
              .map((item) => {
                return item.replace("secure;", "");
              })
              .map((item) => {
                return item.replace("Lax", "None");
              })
              .map((item) => {
                return item.replace(/domain.*?/, "localhost");
              });
            delete proxyRes.headers["set-cookie"];
            proxyRes.headers["set-cookie"] = newCookie;
          }
        },
      },
    ],
  },
};


使用上述方法配置本地调用服务端API,会出现本地页面挂载不上去的问题,一直跑的是环境上的页面。

2, angular前端本地调用后端API

常见问题
页面没有自动打开验证界面

在本地页面访问

portal-xxxx/xxxxxwork/xxfault.html#/home

之后本地页面会打开验证界面。

3,angular解决的问题

1,使用模块解决分工协作的问题

4,第三方组件库

angular官方自己的Schemantics体系更多的应该看作前端框架的应用市场,目前基本所有的angular组件库都可以像应用市场一样通过ng命令进行安装。并且通过angular生态统一管理。

1,第三方组件初始化

ng add @angular/material //初始化material design工程。
ng add @angular/pwa //为当前项目增加pwa支持。

5,schematics

schematics是针对于现代web应用的工作流工具,其支持的本质上是一种低代码平台,由于angular的template本身代表着视图层,或者可以当做config文件,angular做这种低代码生成工具很适合。