摘要:今天我們實現單頁面應用中路由變化設置頁面標題,來優化用戶的用戶體驗。在中,解決起來要比容易得多,我們可以通過注入一個,在路由變化事件中使用提供的來動態更新頁面標題。
現在很多web網站都采用了SPA單頁應用,單頁面有很多優點:用戶體驗好、應用響應快、對服務器壓力小 等等。同時也有一些缺點:首次加載資源太多,不利于SEO,前進、后退、地址欄需要手動管理。今天我們實現Angular單頁面應用中路由變化設置頁面標題,來優化用戶的用戶體驗??梢韵热ゾ蚪鹂聪滦Ч?。稀土掘金
在AngularJS(1.x)中動態設置頁面標題通常是通過一個全局$rootScope對象來完成的,通過$rootScope對象監聽路由變化獲取當前路由信息并映射到頁面標題。在Angular(v2 +)中,解決起來要比1.x容易得多,我們可以通過注入一個provider,在路由變化事件中使用provider提供的API來動態更新頁面標題。
Title Service在angular中,我們可以通過Title來設置頁面標題。我們從platform-browser導入Title, 同時也導入Router。
import { Title } from "@angular/platform-browser"; import { Router } from "@angular/router";
導入之后,我們在組件的構造函數中注入他們
@Component({ selector: "app-root", templateUrl: `Hello world!` }) export class AppComponent { constructor(private router: Router, private titleService: Title) {} }
在使用Title之前,我們先看下Title是如何定義的
export class Title { /** * Get the title of the current HTML document. * @returns {string} */ getTitle(): string { return getDOM().getTitle(); } /** * Set the title of the current HTML document. * @param newTitle */ setTitle(newTitle: string) { getDOM().setTitle(newTitle); } }
Title類有兩個方法,一個用來獲取頁面標題getTitle, 一個是用來設置頁面標題的setTitle
要更新頁面標題,我們可以簡單的調用setTitle方法:
@Component({...}) export class AppComponent implements OnInit { constructor(private router: Router, private titleService: Title) {} ngOnInit() { this.titleService.setTitle("My awesome app"); } }
這樣就可以設置我們的頁面標題了,但是很不優雅。我們接著往下看。
在AngularJS中,我們可以使用ui-router為每個路由添加一個自定義對象,自定義的對象在路由器的狀態鏈中繼承:
// AngularJS 1.x + ui-router .config(function ($stateProvider) { $stateProvider .state("about", { url: "/about", component: "about", data: { title: "About page" } }); });
在Angular2+中,我們也可以為每個路由定義一個data對象,然后再在監聽路由變化時做一些額外的邏輯處理就可以實現動態設置頁面標題。首先,我們定義一個基本的路由:
const routes: Routes = [{ path: "calendar", component: CalendarComponent, children: [ { path: "", redirectTo: "new", pathMatch: "full" }, { path: "all", component: CalendarListComponent }, { path: "new", component: CalendarEventComponent }, { path: ":id", component: CalendarEventComponent } ] }];
在這里定義一個日歷應用,他有一個路由/calendar, 還有三個子路由, /all對應日歷列表頁,new對應新建日歷,:id對應日歷詳情。現在,我們定義一個data對象然后設置一個title屬性來作為每個頁面的標題。
const routes: Routes = [{ path: "calendar", component: CalendarComponent, children: [ { path: "", redirectTo: "new", pathMatch: "full" }, { path: "all", component: CalendarListComponent, data: { title: "My Calendar" } }, { path: "new", component: CalendarEventComponent, data: { title: "New Calendar Entry" } }, { path: ":id", component: CalendarEventComponent, data: { title: "Calendar Entry" } } ] }];
好了,路由定義完了,現在我們看下如何監聽路由變化
Routing eventsAngular路由配置非常簡單,但是路由通過Observables使用起來也非常強大。
我們可以在根組件中全局監聽路由的變化:
ngOnInit() { this.router.events .subscribe((event) => { // example: NavigationStart, RoutesRecognized, NavigationEnd console.log(event); }); }
我們要做的就是在導航結束時獲取到定義的數據然后設置頁面標題,可以檢查 NavigationStart, RoutesRecognized, NavigationEnd 哪種事件是我們需要的方式,理想情況下NavigationEnd,我們可以這么做:
this.router.events .subscribe((event) => { if (event instanceof NavigationEnd) { // 當導航成功結束時執行 console.log("NavigationEnd:", event); } });
這樣我們就可以在導航成功結束時做一些邏輯了,因為Angular路由器是reactive響應式的,所以我們可以使用 RxJS 實現更多的邏輯,我們來導入以下操作符:
import "rxjs/add/operator/filter"; import "rxjs/add/operator/map"; import "rxjs/add/operator/mergeMap";
現在我們已經添加了 filter,map 和 mergeMap 三個操作符,我們可以過濾出導航結束的事件:
this.router.events .filter(event => event instanceof NavigationEnd) .subscribe((event) => { console.log("NavigationEnd:", event); });
其次,因為我們已經注入了Router類,我們可以使用 routerState 來獲取路由狀態樹得到最后一個導航成功的路由:
this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.router.routerState.root) .subscribe((event) => { console.log("NavigationEnd:", event); });
然而,一個更好的方式就是使用 ActivatedRoute 來代替 routerState.root, 我們可以將其ActivatedRoute注入類中:
import { Router, NavigationEnd, ActivatedRoute } from "@angular/router"; @Component({...}) export class AppComponent implements OnInit { constructor( private router: Router, private activatedRoute: ActivatedRoute, private titleService: Title ) {} ngOnInit() { // our code is in here } }
注入之后我們再來優化下:
this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.activatedRoute) .subscribe((event) => { console.log("NavigationEnd:", event); });
我們使用 map 轉換了我們觀察到的內容,返回一個新的對象 this.activatedRoute 在 stream 流中繼續執行。 我們使用 filter(過濾出導航成功結束) 和 map(返回我們的路由狀態樹) 成功地返回我們想要的事件類型 NavigationEnd。
接下來是最有意思的部分,我們將創建一個while循環遍歷狀態樹得到最后激活的 route,然后將其作為結果返回到流中:
this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.activatedRoute) .map(route => { while (route.firstChild) route = route.firstChild; return route; }) .subscribe((event) => { console.log("NavigationEnd:", event); });
接下來我們可以通過路由配置的屬性來獲取相應的頁面標題。然后,我們還需要另外兩個運算符:
this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.activatedRoute) .map(route => { while (route.firstChild) route = route.firstChild; return route; }) .filter(route => route.outlet === "primary") // 過濾出未命名的outlet,.mergeMap(route => route.data) // 獲取路由配置數據 .subscribe((event) => { console.log("NavigationEnd:", event); });
現在我們 titleService 只需要實現:
.subscribe((event) => this.titleService.setTitle(event["title"]));
下面看一下最終代碼:
import "rxjs/add/operator/filter"; import "rxjs/add/operator/map"; import "rxjs/add/operator/mergeMap"; import { Component, OnInit } from "@angular/core"; import { Router, NavigationEnd, ActivatedRoute } from "@angular/router"; import { Title } from "@angular/platform-browser"; @Component({...}) export class AppComponent implements OnInit { constructor( private router: Router, private activatedRoute: ActivatedRoute, private titleService: Title ) {} ngOnInit() { this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.activatedRoute) .map(route => { while (route.firstChild) route = route.firstChild; return route; }) .filter(route => route.outlet === "primary") .mergeMap(route => route.data) .subscribe((event) => this.titleService.setTitle(event["title"])); } }
本文翻譯自dynamic-page-titles-angular-2-router-events, 本人水平有限,如果有翻譯不好的地方歡迎大家聯系我
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83725.html
摘要:文件定義在通過路由定義標題首頁首頁通過動態調用標題在里面定義通過監聽的變化來動態調用標題首頁首頁文件在里同過頭部里的動態調用首頁 js文件 定義module var app = angular.module(app, [ngRoute]); 在config通過路由定義標題 app.config([$routeProvider, $locationProvider, function ...
摘要:該內的內容會根據路由的變化而變化。配置,用來定義路由規則。由此我們就需要另一個第三方路由模塊,叫做,當然它是基于開發的。造成這種現象的最根本原因路由沒有明確的父子層級關系。監聽路由路由狀態發生改變時可以通過監聽,通過注入實現狀態的管理。 何為路由 路由機制運可以實現多視圖的單頁Web應用(single page web application,SPA)。 單頁應用在使用期間不會重新加載...
摘要:首先,我們需要在入口頁面的中配置根路徑然后創建一個路由模塊路由配置在主模塊中導入配置好的路由模塊而在頁面中需要一個容器去承載上面代碼中的定義了用戶點擊后的路由跳轉,定義該路由激活時的樣式類。 剛實習的時候用過AngularJS,那時候真的是連原生JavaScript都不會寫,依樣畫葫蘆做了幾個管理后臺。然后突然換項目了,AngularJS就不寫了,感覺前前后后接觸了一年多的Angula...
摘要:監聽的變動省略其他代碼省略其他代碼這樣,我們就初步實現了一個路由,那么接下來,我們來看看路由怎么實現。 前言 用過現代前端框架的同學,對前端路由一定不陌生, vue, react, angular 都有自己的 router, 那么你對 router 的工作原理了解嗎?如果還不了解, 那么請跟我一起來手寫一個簡單的前端路由, 順便了解一下. 實現路由的2種方式 hash模式 histo...
閱讀 3309·2021-11-24 09:39
閱讀 2824·2021-10-12 10:20
閱讀 1926·2019-08-30 15:53
閱讀 3086·2019-08-30 14:14
閱讀 2616·2019-08-29 15:36
閱讀 1134·2019-08-29 14:11
閱讀 1964·2019-08-26 13:51
閱讀 3424·2019-08-26 13:23