天天看点

使用 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 方法来检测平台并采取相应的行动。