摘要:今天我們實現(xiàn)單頁面應用中路由變化設置頁面標題,來優(yōu)化用戶的用戶體驗。在中,解決起來要比容易得多,我們可以通過注入一個,在路由變化事件中使用提供的來動態(tài)更新頁面標題。
現(xiàn)在很多web網(wǎng)站都采用了SPA單頁應用,單頁面有很多優(yōu)點:用戶體驗好、應用響應快、對服務器壓力小 等等。同時也有一些缺點:首次加載資源太多,不利于SEO,前進、后退、地址欄需要手動管理。今天我們實現(xiàn)Angular單頁面應用中路由變化設置頁面標題,來優(yōu)化用戶的用戶體驗??梢韵热ゾ蚪鹂聪滦ЧO⊥辆蚪?/p>
在AngularJS(1.x)中動態(tài)設置頁面標題通常是通過一個全局$rootScope對象來完成的,通過$rootScope對象監(jiān)聽路由變化獲取當前路由信息并映射到頁面標題。在Angular(v2 +)中,解決起來要比1.x容易得多,我們可以通過注入一個provider,在路由變化事件中使用provider提供的API來動態(tài)更新頁面標題。
Title Service在angular中,我們可以通過Title來設置頁面標題。我們從platform-browser導入Title, 同時也導入Router。
import { Title } from "@angular/platform-browser"; import { Router } from "@angular/router";
導入之后,我們在組件的構造函數(shù)中注入他們
@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
要更新頁面標題,我們可以簡單的調(diào)用setTitle方法:
@Component({...}) export class AppComponent implements OnInit { constructor(private router: Router, private titleService: Title) {} ngOnInit() { this.titleService.setTitle("My awesome app"); } }
這樣就可以設置我們的頁面標題了,但是很不優(yōu)雅。我們接著往下看。
在AngularJS中,我們可以使用ui-router為每個路由添加一個自定義對象,自定義的對象在路由器的狀態(tài)鏈中繼承:
// AngularJS 1.x + ui-router .config(function ($stateProvider) { $stateProvider .state("about", { url: "/about", component: "about", data: { title: "About page" } }); });
在Angular2+中,我們也可以為每個路由定義一個data對象,然后再在監(jiān)聽路由變化時做一些額外的邏輯處理就可以實現(xiàn)動態(tài)設置頁面標題。首先,我們定義一個基本的路由:
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對應日歷詳情?,F(xiàn)在,我們定義一個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" } } ] }];
好了,路由定義完了,現(xiàn)在我們看下如何監(jiān)聽路由變化
Routing eventsAngular路由配置非常簡單,但是路由通過Observables使用起來也非常強大。
我們可以在根組件中全局監(jiān)聽路由的變化:
ngOnInit() { this.router.events .subscribe((event) => { // example: NavigationStart, RoutesRecognized, NavigationEnd console.log(event); }); }
我們要做的就是在導航結束時獲取到定義的數(shù)據(jù)然后設置頁面標題,可以檢查 NavigationStart, RoutesRecognized, NavigationEnd 哪種事件是我們需要的方式,理想情況下NavigationEnd,我們可以這么做:
this.router.events .subscribe((event) => { if (event instanceof NavigationEnd) { // 當導航成功結束時執(zhí)行 console.log("NavigationEnd:", event); } });
這樣我們就可以在導航成功結束時做一些邏輯了,因為Angular路由器是reactive響應式的,所以我們可以使用 RxJS 實現(xiàn)更多的邏輯,我們來導入以下操作符:
import "rxjs/add/operator/filter"; import "rxjs/add/operator/map"; import "rxjs/add/operator/mergeMap";
現(xiàn)在我們已經(jīng)添加了 filter,map 和 mergeMap 三個操作符,我們可以過濾出導航結束的事件:
this.router.events .filter(event => event instanceof NavigationEnd) .subscribe((event) => { console.log("NavigationEnd:", event); });
其次,因為我們已經(jīng)注入了Router類,我們可以使用 routerState 來獲取路由狀態(tài)樹得到最后一個導航成功的路由:
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 } }
注入之后我們再來優(yōu)化下:
this.router.events .filter(event => event instanceof NavigationEnd) .map(() => this.activatedRoute) .subscribe((event) => { console.log("NavigationEnd:", event); });
我們使用 map 轉(zhuǎn)換了我們觀察到的內(nèi)容,返回一個新的對象 this.activatedRoute 在 stream 流中繼續(xù)執(zhí)行。 我們使用 filter(過濾出導航成功結束) 和 map(返回我們的路由狀態(tài)樹) 成功地返回我們想要的事件類型 NavigationEnd。
接下來是最有意思的部分,我們將創(chuàng)建一個while循環(huán)遍歷狀態(tài)樹得到最后激活的 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) // 獲取路由配置數(shù)據(jù) .subscribe((event) => { console.log("NavigationEnd:", event); });
現(xiàn)在我們 titleService 只需要實現(xiàn):
.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, 本人水平有限,如果有翻譯不好的地方歡迎大家聯(lián)系我
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/83725.html
摘要:文件定義在通過路由定義標題首頁首頁通過動態(tài)調(diào)用標題在里面定義通過監(jiān)聽的變化來動態(tài)調(diào)用標題首頁首頁文件在里同過頭部里的動態(tài)調(diào)用首頁 js文件 定義module var app = angular.module(app, [ngRoute]); 在config通過路由定義標題 app.config([$routeProvider, $locationProvider, function ...
摘要:該內(nèi)的內(nèi)容會根據(jù)路由的變化而變化。配置,用來定義路由規(guī)則。由此我們就需要另一個第三方路由模塊,叫做,當然它是基于開發(fā)的。造成這種現(xiàn)象的最根本原因路由沒有明確的父子層級關系。監(jiān)聽路由路由狀態(tài)發(fā)生改變時可以通過監(jiān)聽,通過注入實現(xiàn)狀態(tài)的管理。 何為路由 路由機制運可以實現(xiàn)多視圖的單頁Web應用(single page web application,SPA)。 單頁應用在使用期間不會重新加載...
摘要:當左右服務都被解析并返回時,會以服務為參數(shù)去調(diào)用組件的構造函數(shù)。發(fā)送或廣播的消息應該限定在最小的作用域。置頂一個通過,發(fā)送的消息列表并且窒息的管理以防止命名沖突在需要格式化數(shù)據(jù)時,將格式 angular 數(shù)據(jù)雙向綁定的框架 提供數(shù)據(jù)綁定,DOM指令。angular,定義了一套規(guī)則,開發(fā)中就必須遵守規(guī)則,這套規(guī)則為項目提供了一套解決方案。 模塊,組件,模板,元數(shù)據(jù),數(shù)據(jù)綁定, 指令,服務...
摘要:首先,我們需要在入口頁面的中配置根路徑然后創(chuàng)建一個路由模塊路由配置在主模塊中導入配置好的路由模塊而在頁面中需要一個容器去承載上面代碼中的定義了用戶點擊后的路由跳轉(zhuǎn),定義該路由激活時的樣式類。 剛實習的時候用過AngularJS,那時候真的是連原生JavaScript都不會寫,依樣畫葫蘆做了幾個管理后臺。然后突然換項目了,AngularJS就不寫了,感覺前前后后接觸了一年多的Angula...
摘要:監(jiān)聽的變動省略其他代碼省略其他代碼這樣,我們就初步實現(xiàn)了一個路由,那么接下來,我們來看看路由怎么實現(xiàn)。 前言 用過現(xiàn)代前端框架的同學,對前端路由一定不陌生, vue, react, angular 都有自己的 router, 那么你對 router 的工作原理了解嗎?如果還不了解, 那么請跟我一起來手寫一個簡單的前端路由, 順便了解一下. 實現(xiàn)路由的2種方式 hash模式 histo...
閱讀 3369·2021-11-24 09:39
閱讀 2924·2021-10-12 10:20
閱讀 1998·2019-08-30 15:53
閱讀 3146·2019-08-30 14:14
閱讀 2659·2019-08-29 15:36
閱讀 1196·2019-08-29 14:11
閱讀 2064·2019-08-26 13:51
閱讀 3493·2019-08-26 13:23