30

Angular开发技巧

 5 years ago
source link: https://worktile.com/blog/tech/Angular-skill?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
由于之前有幸去参加了ngChina2018开发者大会,听了will保哥分享了Angular开发技巧,自己接触Angular也有差不多快一年的时间了,所以打算对Angular开发中的一些技巧做一个整理

工具篇

所谓 “工欲善其事,必先利其器”,下面我会介绍 如何打磨 `VS Code` 这把利器
  1. 抛弃 资源管理器 ,使用快捷键 Commd + P 来查找文档,默认会展示最近打开的文档,并且支持模糊搜索文件

    2uI3EvM.png!web
  2. 快速打开最近文档:前进 Ctrl+:heavy_plus_sign: 后退 Ctrl+:heavy_minus_sign:

  3. 灵活使用VS Code重构功能,可以通过快捷键 Command + 对代码进行重构

    ZbqmIvn.png!web
  4. 安装插件 Angular Extension Pack (认准will保哥出品),这个插件集成了很多提升Angular开发效率的插件,比如:

    在 TS中实用 `ng-import-*` 导入常见的类
    模板编辑的时候实用 ` a-*** `  快速使用Angular的组件和指令 (Angular v7 Snippets)
    实用 ` ng-* ` 来生成常用的ng代码段,创建 Component,Directive 等 (Angular Snippets)

    通过快捷键把JSON转换成TS类

    Ctrl+Alt+V 把粘贴板中的JSON 转为 Typescript
    Ctrl+Alt+S 将选中的JSON 生成对应的 Typescript

    还有一个值得一提的一个比较实用的功能,通过快捷键来 快速切换组件对应的不同的文件 (Angular2-switcher)

    QJbyEnu.png!web

    还有很多其他功能,插件中有详细介绍 `Angular Extension Pack

  5. 安装插件 Clipboard History , 这个插件会存储你最近的拷贝的记录,方便记录和粘贴最近几次的拷贝内容

    MvyIvuY.png!web
  6. 安装插件 Local History ,这个插件用于维护文件的本地历史记录。每次修改文件时,旧内容的副本都会保留在本地历史记录中,你可以随时将文件与历史记录中的任何旧版本进行比较,如果发生意外时,可以帮助我们恢复丢失的内容,需要注意的是它会生成一个 .history 的文件夹进行本地修改的备份,所以我们需要再 .gitignore 排除这个文件夹,避免将其提交到git仓储。

  7. 安装插件 Prettier - Code formatter ,这是一个代码格式化的插件,用过几个格式化的插件,个人感觉最好用的一个,更适合Angular开发

  8. 安装 Chrome 插件 Angular Angury 进行调试工作,可以查看 Component 的 State,Router Tree,NgModules的一些状态 (这个插件在复杂项目中并不是特别好用,包括对一些动态组件的支持比较差,但是在一些简单的项目中,或者新手在学习的时候安装这个插件比较方便调试排错)

    mIbI7fm.png!web
    Nf2qAf6.png!web

开发篇

下面会介绍一些Angular开发中的技巧
  1. 使用模板语言 as , 使用 as 对一些嵌套结构深的属性进行重命名

    改进前:

    <div *ngFor="let queue of fileUploadQueues">
        <div class="icon" *ngIf="queue.result.file.icon">{{ queue.result.file.icon }}</div>
        <div class="name" *ngIf="queue.result.file.name">{{ queue.result.file.name }}</div>
        <div class="size" *ngIf="queue.result.file.size">{{ queue.result.file.size }}</div>
    </div>

    改进后:

    <div *ngFor="let queue of fileUploadQueues">
      <ng-container *ngIf="queue.result.file as file">
           <div class="icon" *ngIf="file.icon">{{ file.icon }}</div>
           <div class="name" *ngIf="file.name">{{ file.name }}</div>
           <div class="size" *ngIf="file.size">{{ file.size }}</div>
      </ng-container>
    </div>
  2. 灵活使用 *ngIfElse ,很多人其实一直在写 *ngIf 并不知道其实Angular支持 else 的写法 *ngIf="条件 ; else 模板" ,看看下面这两段代码

    改进前:

    <div *ngIf="(data$ | async).length > 0">
       ...
    </div>
    <div *ngIf="!(data$ | async).length > 0">
       没有数据
    </div>

    改进后:

    <div *ngIf="(data$ | async).length > 0; else emptyTemplate;">
       ...
    </div>
    <ng-template  #emptyTemplate>
       没有数据
    </ng-template>

    改进前的写法,也能实现同样的效果,但是因为数据是通过 async 订阅的,第一种写法相当于进行了两次订阅,当然也可以用 as 来解决,这里只是一个示例。

    还有一种情况,在条件多的时候,通过第一种方式写的话,如果条件有修改的话,必须要对取反后的条件进行维护, 而用 ngIfElse 的方式则只需要进行一次维护。

  3. 使用 ng-container 对代码进行整理,使代码更清晰,提升代码的可读性

    <ng-container *ngIf="type === 1">
       ...
    </ng-container>
    <ng-container *ngIf="type === 2">
       ...
    </ng-container>
    <ng-container *ngIf="type === 3">
       ...
    </ng-container>
  4. @ViewChild 读取指定类型的实例

    <input #input thyInput  [thyAutofocus]="true" />

    上面这行代码有三个实例 ElementRefThyInputComponentThyAutoFocusDirective ,在某些情况下如果我们要获取指定类型的实例应该怎么做呢?

    @ViewChild('input', { read:ThyInputComponent })  inputComponent : ThyInputComponent ;
  5. 使用 async 管道,直接在模板中订阅流,而不必将结果存储在中间属性中,当组件被销毁时,Angular将会自动取消订阅。

    <div *ngFor="let item of data$ | async">
       ...
    </div>

    在一些情况下,我们可能需要重复使用订阅的数据,但是我们又不能每次使用的时候都用 async 去订阅,所以我们可以通过刚才说的 as 对齐进行重命名。

    <div *ngFor="let item of data$ | async as data">
       <span>一共有{{data.length}}条数据</span>
    </div>
  6. 使用 takeUntil 来管理订阅

    在某些复杂的业务中,我们可能需要订阅多个流,一个一个去取消订阅又繁琐,又会产生很多冗余代码,不利于代码的维护。这时候我们可以 takeUntil 来管理多个订阅,统一取消订阅。

    private _ngUnsubscribe$ = new Subject();
    
    ngOnInit() {
     this.students$.pipe(
        takeUntil(_ngUnsubscribe$)
     ).subscribe(() => {
             ...
     });
     this.books$.pipe(
        takeUntil(_ngUnsubscribe$)
     ).subscribe(() => {
             ...
     });
    }
    ngOnDestroy() {
      this._ngUnsubscribe$.next();
      this._ngUnsubscribe$.complete();
    }
  7. 合理使用 ngZone runOutsideAngular 来提升应用性能

    我们知道Angular可以自动处理变化检测,这是因为它使用了 zone.js ,简单的来说, zone.js 就是通过打补丁的方式来拦截浏览器的事件,然后进行变化检测,但是变化检测是极其消耗资源的,如果绑定了大量的事件,那么就会造成性能问题,所以我们可以使用 runOutsideAngular 来减少不必要的变化检测。

    this.ngZone.runOutsideAngular(() => {
       this.renderer.listen(this.elementRef.nativeElement, 'keydown', event => {
          const keyCode = event.which || event.keyCode;
             if (keyCode === keycodes.ENTER) {
                  event.preventDefault();
                  this.ngZone.run(() => {
                      this.thyEnter.emit(event);
                  });
             }
       });
    });

    上面这段代码是绑定一个回车事件,如果不使用 runOutsideAngular 的话,只要触发键盘输入事件,就会执行变化检测,这时候我们可以用 runOutsideAngular 在只有为enter事件的时候,去调用 ngZone.run() 主动触发变化检测

  8. 灵活使用 ngTemplateOutlet 来实现递归

    <ng-container *ngFor="let node of treeNodes;" [ngTemplateOutlet]="nodeTemplate" 
             [ngTemplateOutletContext]="{node: node}">
    </ng-container>
    
    <ng-template #nodeTemplate let-node="node">
         <div class='title'>{{node.title}}</div>
          <ng-container *ngFor="let child of node?.children;"  [ngTemplateOutlet]="nodeTemplate"
                         [ngTemplateOutletContext]="{node: child}">
           </ng-container>
    </ng-template>

    在我们实际开发的过程中,经常会展示一些树形结构的数据,如果业务场景比较简单,可以通过Angular的 ngTemplateOutlet 来实现递归展示,如果业务复杂,建议还是通过组件的方式来实现。

写在最后

上面是我这一年Angular开发的过程中积累的一些小技巧(可能还有没想起来的,我想起来会慢慢的往上补),大家如果发现有错误的地方,请指正。其实去年就写好这篇文章,但是总感觉缺点什么,不过无所谓了~~ 希望能给Angular学习者提供帮助~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK