天天看點

使用 Angular Transfer State 的一個具體例子

Using TransferState API in an Angular v5 Universal App

讓我們用一個具體的例子來說明這篇文章。 我們有一個天氣應用程式,在其側邊欄中顯示城市清單。 當您單擊城市名稱時,該應用程式會顯示該城市的目前天氣。

因為我們希望我們的應用程式是可抓取和可索引的,是以我們使它通用:城市頁面在伺服器上呈現,存儲為 HTML 檔案并由 HTTP 伺服器提供服務。 這些頁面将包含浏覽器應用程式,是以使用者可以在加載第一頁後使用 Angular 的強大功能繼續在應用程式中導航。

您可以按照以下步驟嘗試這個簡單的示例。

使用下列指令将這個例子 clone 到本地:

使用 Angular Transfer State 的一個具體例子

您現在可以使用首選的 HTTP 伺服器為 dist 目錄提供服務。

現在,如果您直接通路頁面 http://your-domain/Paris(這是通路者來自搜尋引擎的典型情況),您可以觀察到頁面閃爍 - 這是因為内容已經存在并且已經下載下傳到本地了,然後浏覽器應用程式會重新加載并再次顯示。

TransferState to the rescue

Angular v5 中引入的 TransferState API 可以幫助解決這種情況。 它可以将資料從應用程式的伺服器端傳輸到浏覽器應用程式。

為此,伺服器應用程式将在它生成的 HTML 頁面中添加我們要傳輸的資料。

包含在此生成的 HTML 頁面中的浏覽器應用程式将能夠讀取此資料。

在這個分支檢視解決方案。

使用 Angular Transfer State 的一個具體例子
使用 Angular Transfer State 的一個具體例子

現在,在為元件提供資料的解析器中,我們可以使用 TransferState API:

在伺服器上,我們首先注冊 onSerialize 以提供我們将下載下傳的資料,然後我們從我們的資料提供者那裡擷取資料,這裡是一個 HTTP GET 請求。

在浏覽器上,我們使用get方法來擷取server提供的資料,我們直接提供這些資料。 我們還從傳輸狀态中删除了提供的資料,是以頁面的重新加載将不再使用提供的資料。

我們可以通過調用 hasKey 方法來檢測我們是在伺服器上還是在浏覽器應用程式上。 此方法僅在浏覽器中傳回 true。

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<CityWeather> {
    const found = this.transferState.hasKey(RESULT_KEY);
    if (found) {
      const res = Observable.of(this.transferState.get<CityWeather>(RESULT_KEY, null));
      this.transferState.remove(RESULT_KEY);
      return res;
    } else {
      this.transferState.onSerialize(RESULT_KEY, () => this.result);
      const name = route.params['city'];
      return this.http.get<CityWeather>('https://api.openweathermap.org/data/2.5/weather?q=' + name + '&units=metric&APPID=' + this.key)
        .do(result => this.result = result);
    }
  }
      

因為我們是調用remove方法移除提供的資料,是以浏覽器顯示的以下頁面會調用onSerialize方法,但是這個方法沒有效果,因為toJson隻在服務端調用。

一個更清晰的解決方案是使用 isPlatformServer 和 isPlatformBrowser 方法來檢測平台并采取相應的行動。