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