今天我們終於要來解決很久之前提到的todo代辦事項,剛進入要等一下資料才會出來會造成使用者體驗不佳的問題
反應時間短,可能還行,但如果要等個幾秒,那就有可能造成使用者誤會
想說網站是沒資料,還是當掉了呢?
而網路資料本來就需要時間從伺服器取回來,所以等待時間是不可避免的
那這時候就要用其他策略性作法來解決這個體驗的問題
這篇要來教一個策略,就是使用預載資料的做法,就是將資料載入完之後,畫面在顯示
如此當畫面出現的時候,資料也準備好了所以會同時會在畫面上,這樣就不會剛進去時資料還沒出來,過一陣子才又冒出來
首先先下一個產生resolve的指令
ng g r todo
那這會產生resolve的基本格式,這是作為angular的預載機制的一個檔案類型
這邊我們需要依賴注入TodoApiService,這裡也可以發現為什麼要把api的部分切成service,因為很多地方可能都會用到
constructor(private todoApiService:TodoApiService){}
那依賴注入TodoApiService要做什麼?就是要在resolve這邊先取得todo的資料
整個寫完的程式碼如下
import { Todo } from './../@models/todo.model';
import { TodoApiService } from './../@services/todo-api.service';
import { Injectable } from '@angular/core';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class TodoResolver implements Resolve<Todo[]> {
constructor(private todoApiService: TodoApiService, private todoService: TodoService) { }
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Todo[]> {
const id = route.paramMap.get('id') as string;
this.todoService.gid = id;
return this.todoApiService.取得資料(id);
}
}
這邊用到上一篇的技巧,因為我們現在有不同的代辦事項
所以要先取得id後才能撈取指定的代辦事項,而在resolve中一樣可以取得id,用法如上
取得id後,我們就可以繼續取得指定代辦事項
最後我們再到todo-routing.module.ts,加上預載資料的設定
const routes: Routes = [
{ path: 'list', component: TodoListComponent },
{
path: 'content/:id',
children: [
{
path: ':action',
component: TodoContentComponent,
resolve: { todoList: TodoResolver }
},
{ path: '', redirectTo: 'All', pathMatch: 'full' }
]
},
{ path: '', redirectTo: 'list', pathMatch: 'full' }
];
就是在該路由設定中,多一個resolve,後面的todoList是自訂的變數,隨後放的是剛剛寫的TodoResolver
這樣在進入這一頁前,會先執行TodoResolver,並且在進入TodoContentComponent後,就可以拿到預載完的資料
那要怎麼取得呢?我們就到todo-content.component.ts中來取得
constructor(private todoService: TodoService,
private route: ActivatedRoute) { }
ngOnInit() {
this.todoService.todoDataList = [];
this.route.data.subscribe(data=>{
this.todoService.todoDataList = data['todoList'];
this.todoService.ready();
});
}
可以使用this.route.data.subscribe
來取得todoDataList的資料,如上
回到畫面上看一下效果有沒有出現
可以發現,我們這次進去後,畫面就已經有資料了,不會再過一陣子才出來
那這邊的話還有另一個寫法
ngOnInit() {
this.todoService.todoDataList = this.route.snapshot.data['todoList'];
}
用snapshot
一樣可以取得,但一樣會有上一篇的問題,如果是相同的component換頁,這行不會再執行第二次,要注意一下
最後todo-list這邊也是需要設置預先載入,就留給大家練習
到這邊,相信一定會有人覺得哪裡怪怪的
沒錯,就是預載資料本身這件事就有違和之處
我們只是將等待時間往前移了,本來等待資料在進入頁面之後,變成移到切換頁面之前
那這樣不就跟MPA網站的一樣,是等待資料全部準備好,才會進入下一頁
那體驗感不就跟MPA又變成一樣了嗎?不能馬上切換畫面過去
沒錯,在頁面需要資料的情況下,我們還是得花時間下載資料才行,只有在不需要資料的情況下,畫面才能直接切換過去
但大部分的頁面都是動態頁面,資料都是動態的,所以基本上都要進去之後才下載
雖然流程似乎跟MPA一樣了,但其實效能上SPA還是大勝
我們仔細觀察,MPA是整個網頁、JS、CSS和相關圖片檔案都做重新載入
但我們SPA只有載入資料而已,所以雖然載入動態頁面的流程變得差不多
不過兩者下載的資料量跟處理,可是天差地遠,SPA雖然在載資料的時候一樣要等,但等的時間絕對是贏過MPA
最後,我們還有一個地方要解決,就是當我們按下需要預載的頁面時,畫面會沒有任何動作,但其實正在預載資料,載完才會切換過去
不過這時就會讓使用者感到疑惑?是系統當了,還是系統效能太差,怎麼卡住了?
所以,我們在這邊還需要自己設計一個載入條,告知使用者,有收到換頁要求,正在載入中喔
那下一篇,就會來示範載入條要怎麼做
回到策略面選擇問題
其實並非所有情況都要預先載入,視情況我們有些資料也是可以在畫面出現之後,在慢慢載入
那我個人認為,速度在3秒內,畫面必要資料,可以考慮預先載入
那須要等很久的資料或非必要資料,像fb的貼文,就可以等到畫面出來之後再載入就好,那當然此類資料也要額外設置提示訊息,不能讓使用者看著一片空白的畫面
用前端框架,真的需要考慮很多事情,做很多使用者體驗的設計,並且要視情況選擇不同的顯示策略
所以前端常常花的時間都不是功能面,而是顯示面的設計反而會占掉大多數的開發時間
如果什麼都不做,其實也很快可以開發完,但既然用了前端框架,那就是要做~~~
範例檔:下載