2

前言

这星期主要实现了一个搜索功能,,便于用户在选择项比较多的时候快速选择自己想要选的那个。

防抖

本着是一个隐藏的搜索框,如果在蹦出搜索框的同时右边有一个提交按钮的话会显得比较突兀,也是本着让用户少点一次的原则,就想做成一个类似于搜索提示的效果,这里用到了防抖机制。
我们希望当我们在搜索框中输入关键字时,系统能够自动搜索。但是系统无法判断我们输入到什么时候是他想要的关键字。这是就用到了防抖,通过搜索框内容改变的时间判断是否开始搜索,当一段时间内搜索关键字不改变时,开始调用搜索方法。当搜索关键字改变时,重置时间。
比如我们搜索河北工业大学
在不加入防抖时,过程是这样的:
“河” -- 请求1次后台(无用功)
“河北” -- 请求1次后台(无用功)
“河北工” -- 请求1次后台(无用功)
“河北工业” -- 请求1次后台(无用功)
“河北工业大学” -- 请求1次后台(用户想要的)
在我们加入防抖时,过程是这样的:
“河” -- 不请求后台
“河北” -- 等一秒,请求1次后台,但是搜索后的内容还是很多,继续输入
“河北工” -- 不请求后台
“河北工业” -- 不请求后台
“河北工业大学” -- 一秒后,请求1次后台(用户想要的)
具体到代码中,我们使用(input)事件判断搜索框内容变化,当内容变化时,会调用指定方法。

<input  *ngIf="this.bindCourseSearch"  (input)="search()" type="text" class="form-control search" placeholder="请输入课程名称或代码" [formControl]="courseCodeOrName"/>

同时c层

searchSubject: Subject<string> = new Subject<string>();

ngOnInit() {
    ...
    this.searchSubject.asObservable().pipe(debounceTime( 1000))
      .subscribe(() => {
        this.codeOrName = this.courseCodeOrName.value;
      });
}

search(): void {
    this.searchSubject.next();
  }

更多关于截流与防抖的应用请看这篇文章:Rxjs防抖与节流在项目中的应用

搜索速度

搜索往往面对很多数据,如何提高搜索速度也是重要的一环

减少请求后台次数

每请求一次后台,便会花费一些时间,所以我们要尽可能的减少请求后台次数。
如果不涉及到分页的话,我们请求一次所有数据后,在前台保存所有数据,以后关键字变更直接调用前台所有数据,减少请求后台所有数据。

/** 用于查询遍历,全部的专业课 */
courseClone: Array<Course>
减少遍历次数

我们在前台直接处理所有数据免不了进行遍历进行过滤,多次遍历也会影响搜索时间。
比如说,我们搜索课程有多个条件,在某一学院下名称或或者代码包含关键字的课程。一开始仿写写好的过滤学院条件代码去写过滤名称或代码的代码。然后先过滤一遍学院,再过滤一遍名称或代码。如果同时过滤二者需要很多判断,防止在空指针,很复杂。所以进行了两次过滤。但是我没有考虑到在v层显示其实也是一遍遍历。
我们可以运用v层的一遍遍历,去进行名称或代码过滤,过滤掉的加个*ngIf不显示即可。

<ng-container *ngIf="getAllByCodeOrName(_course, state.codeOrName)">
    <input class="form-check-input" id="course_{{_course.id}}" type="checkbox" [checked]="state.checkedMap.get(_course.id)"
           (change)="change(_course.id)">
    <label class="form-check-label" for="course_{{_course.id}}">{{_course.code}}&nbsp;{{_course.name}}</label>
</ng-container>

但是涉及到分页不建议这用ngif隐藏,这样会造成一页3条数据一页4条数据的情况。

补充

关于ng-container

<ng-container></ng-container>理解为指令的宿主,并无实际含义
举个例子
我们无法在一个div中添加两个*ngif判断

<!-- Can't do this -->
<div *ngIf="todos" *ngFor="let todo of todos">
  {{ todo.content }}
</div>

这时候我们想到用两个div标签

<div *ngIf="todos">
  <div *ngFor="let todo of todos">
    {{ todo.content }}
  </div>
</div>

但是,这样写多了一个无用的div,我们还可以这样写

<ng-container *ngIf="todos">
  <div *ngFor="let todo of todos">
    {{ todo.content }}
  </div>
</ng-container>

ng-container并不会添加无用的标签。
参考:Angular: The ng-container Element

总结

一个好的项目必定伴随着一段优秀的代码,一段优秀的代码不仅是代码量少,也是时间复杂度低。这需要我们对实现的功能进行重构。一个功能不是实现就可以了,还要实现好。
感谢潘老师的指导。

版权声明

本文作者:河北工业大学梦云智开发团队 - 赵凯强

小强Zzz
1.2k 声望32 粉丝