共计 2412 个字符,预计需要花费 7 分钟才能阅读完成。
Using TransferState API in an Angular v5 Universal App
让咱们用一个具体的例子来阐明这篇文章。咱们有一个天气应用程序,在其侧边栏中显示城市列表。当您单击城市名称时,该应用程序会显示该城市的以后天气。
因为咱们心愿咱们的应用程序是可抓取和可索引的,所以咱们使它通用:城市页面在服务器上出现,存储为 HTML 文件并由 HTTP 服务器提供服务。这些页面将蕴含浏览器应用程序,因而用户能够在加载第一页后应用 Angular 的弱小性能持续在应用程序中导航。
您能够依照以下步骤尝试这个简略的示例。
应用下列命令将这个例子 clone 到本地:
$ git clone https://github.com/feloy/ng-demo-transfer-state
$ cd ng-demo-transfer-state
$ git checkout initial
构建程序:
$ npm install
$ ng build -prod
$ ng build -prod -app server --output-hashing=none
为不同的城市创立不同的页面:
$ node render-page.js /Paris > dist/Paris
$ node render-page.js /London > dist/London
$ node render-page.js /San%20Fransisco > 'dist/San Fransisco'
您当初能够应用首选的 HTTP 服务器为 dist 目录提供服务。
当初,如果您间接拜访页面 http://your-domain/Paris(这是访问者来自搜索引擎的典型状况),您能够察看到页面闪动 – 这是因为内容曾经存在并且曾经下载到本地了,而后浏览器应用程序会从新加载并再次显示。
TransferState to the rescue
Angular v5 中引入的 TransferState API 能够帮忙解决这种状况。它能够将数据从应用程序的服务器端传输到浏览器应用程序。
为此,服务器应用程序将在它生成的 HTML 页面中增加咱们要传输的数据。
蕴含在此生成的 HTML 页面中的浏览器应用程序将可能读取此数据。
在这个分支查看解决方案。
$ git checkout transfer-data
首先在服务器利用上导入 ServerTransferStateModule,在浏览器利用上导入 BrowserTransferStateModule:
// src/app/app.server.module.ts
import {ServerTransferStateModule} from '@angular/platform-server';
[...]
@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
// src/app/app.module.ts
import {BrowserTransferStateModule} from '@angular/platform-browser';
[...]
@NgModule({
declarations: [AppComponent, CityComponent],
imports: [BrowserModule.withServerTransition({ appId: 'ng-demo-transfer-state-app'}),
BrowserTransferStateModule,
[...]
当初,在为组件提供数据的解析器中,咱们能够应用 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 办法来检测平台并采取相应的口头。
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: