Angular 2 利用Router事件和Title实现动态页面标题的方法


Posted in Javascript onAugust 23, 2017

Angular2 为我们提供了名为Title的Service用于修改和获取页面标题,但是如果只是能够在每个页面的ngOnInit方法中为每个页面设置标题岂不是太low了,不符合Angular2高(zhuang)大(bi)的身影。我们想要的结果是在页面改变时能够动态地改变页面标题,如此最好的解决方案就是组合使用Router事件和Title Service。

Title Service

使用Service自然首先要将其引入,不过要注意Title Service并不在@angular/core中,而是在@angular/platform-browser中:

import { Title } from '@angular/platform-browser';

引入之后,自然要将其注入到当前组件中,而这通常利用constructor完成:

import { Title } from '@angular/platform-browser';
import {Component} from '@angular/core';
@Component({})
export class AppComponent {
  constructor(private titleService: Title) {
    // 使用this.title到处浪
  }
}

很显然,Title Service应该有某些操作页面标题的方法,不管通过查找文档还是查找源码我们都能很容易知道其只有两个方法:

  • getTitle() 用于获取当前当前页面的标题
  • setTitle(newTitle: String) 用于设置当前页面的标题

如果只是简单地静态地设置页面标题,则可以在ngOnInit方法中直接使用setTitle方法:

// import bala...
@Component({})
export class AppComponent implements OnInit {
  constructor(private titleService: Title) {
    // 使用this.title到处浪
  }

  ngOnInit() {
    this.titleService.setTitle('New Title Here');
  }
}

在ngOnInit中使用setTitle方法设置文档标题是较好的时机,当然也可以根据自己的需求在任意地方使用setTitle方法。

Router和Router事件

使用Router和使用Title Service流程基本一致,先引入后注入,不过要注意Router和Title Service类似并不位于@angular/core中,而是位于@angular/router中:

import { Title } from '@angular/platform-browser';
import {Component} from '@angular/core';
import {Router} from '@angular/router';
@Component({})
export class AppComponent {
  constructor(private titleService: Title, private router: Router) {
    // 使用this.title和this.router到处浪
  }
}

Router配置

Angular2中通过URL、Router和Component之间的对应关系进行页面之间的跳转,Router把浏览器中的URL看做一个操作指南,据此可导航到一个由客户端生成的视图,并可以把参数传给支撑视图的相应组件。所以我们需要定义路由表:

// import bala...
export const rootRouterConfig: Routes = [
 { path: '', redirectTo: 'home', pathMatch: 'full'},
 { path: 'home', component: HomeComponent, data: {title: 'Home-Liu'} },
 { path: 'about', component: AboutComponent, data: {title: 'About-Liu'} },
 { path: 'github', component: RepoBrowserComponent,
  children: [
   { path: '', component: RepoListComponent, data: {title: 'GitHub List'} },
   { path: ':org', component: RepoListComponent,
    children: [
     { path: '', component: RepoDetailComponent, data: {title: 'Repo'} },
     { path: ':repo', component: RepoDetailComponent, data: {title: 'RepoDetail'} }
    ]
   }]
 },
 { path: 'contact', component: ContactComponent, data: {title: 'Contact-Liu'} }
];

注意路径和组件之间的对应关系,并且为了能够在Router事件中获取到页面标题,我们在路由表中,为一些页面提供了数据data,并在data中设置了表示页面标题的title属性。

Router事件

利用Router事件我们就可以实现动态改变页面标题的目的,不过放置的位置很重要,我们这里选择在AppComponent的ngOnInit方法中利用subscribe订阅Router事件,因为AppComponent是根组件,所以能够订阅所有Router事件:

ngOnInit() {
 this.router.events
  .subscribe((event) => {
   console.log(event);  // 包括NavigationStart, RoutesRecognized, NavigationEnd
  });
}

当然我们这里这对NavigationEnd事件感兴趣:

import {ActivatedRoute} from '@angular/router';
// import bala...

// other codes

ngOnInit() {
 this.router.events
  .subscribe((event) => {
   if (event instanceof NavigationEnd) {
    console.log('NavigationEnd:', event);
   }
  });
}

当然使用这种判断筛选的方式并没有错,但是在现在的前端世界里显得不够优雅,我们应该使用RxJS中的filter达到我们的目的:

import 'rxjs/add/operator/filter';
// import bala...

// other codes

ngOnInit() {
 this.router.events
 .filter(event => event instanceof NavigationEnd) // 筛选原始的Observable:this.router.events
 .subscribe((event) => {
  console.log('NavigationEnd:', event);
 });
}

当然,我们如果想要动态改变某个页面的标题,就需要获取到当前被展示的页面对应的路由信息,而这可以通过ActivatedRoute得到,其使用方式和Title Service及Router类似,不再赘述:

import { Title } from '@angular/platform-browser';
import {Component, OnInit} from '@angular/core';
import {Router, NavigationEnd, ActivatedRoute} from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
@Component({})
export class AppComponent implements OnInit {
 constructor(private titleService: Title, private router: Router, private activatedRoute: ActivatedRoute) {
  // 使用this.title和this.router和this.activatedRoute到处浪
 }

 ngOnInit() {
  this.router.events
  .filter(event => event instanceof NavigationEnd)
  .map(() => this.activatedRoute) // 将filter处理后的Observable再次处理
  .subscribe((event) => {
   console.log('NavigationEnd:', event);
  });
 }
}

注意这里我们又使用了RxJS中的map来更优雅地达成我们目的。

看起来我们已经完(luo)成(suo)很多事情了,但是还不够,我们目前还没有处理子路由,即我们上文路由配置中的children属性,所以我们还需要遍历路由表以便获取到每一个页面对应的路由信息:

ngOnInit() {
 this.router.events
 .filter(event => event instanceof NavigationEnd)
 .map(() => this.activatedRoute)
 .map((route) => {
  while(route.firstChild) {
   route = router.firstChild;
  }
  return route;
 })
 .subscribe((event) => {
  console.log('NavigationEnd:', event);
 });
}

最后,我们还需要获取到我们在路由表中为每个路由传入的data信息,然后再利用Title Service设置页面标题:

ngOnInit() {
 this.router.events
  .filter(event => event instanceof NavigationEnd)
  .map(() => this.activatedRoute)
  .map(route => {
   while (route.firstChild) route = route.firstChild;
   return route;
  })
  .mergeMap(route => route.data)
  .subscribe((event) => this.titleService.setTitle(event['title']));
}

下面是完成的最终代码,或者也可以到GitHub上查看完整代码:

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

@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']));
 }
}

参考文档

Angular2 路由指导

Angualr2 ActivatedRoute文档

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使javascript也能包含文件
Oct 26 Javascript
javascript开发随笔一 preventDefault的必要
Nov 25 Javascript
jquery实现带二级菜单的导航示例
Apr 28 Javascript
详解VUE的状态控制与延时加载刷新
Mar 27 Javascript
Node.js中的http请求客户端示例(request client)
May 04 Javascript
AngularJS全局警告框实现方法示例
May 18 Javascript
vue中组件的过渡动画及实现代码
Nov 21 Javascript
详解如何给React-Router添加路由页面切换时的过渡动画
Apr 25 Javascript
Vue项目服务器部署之子目录部署方法
May 12 Javascript
vue源码中的检测方法的实现
Sep 26 Javascript
vue实现购物车案例
May 30 Javascript
jquery插件懒加载的示例
Oct 24 jQuery
angular2路由切换改变页面title的示例代码
Aug 23 #Javascript
通俗解释JavaScript正则表达式快速记忆
Aug 23 #Javascript
bootstrap fileinput实现文件上传功能
Aug 23 #Javascript
jQuery Position方法使用和兼容性
Aug 23 #jQuery
详解EasyUi控件中的Datagrid
Aug 23 #Javascript
Vue0.1的过滤代码如何添加到Vue2.0直接使用
Aug 23 #Javascript
Bootstrap table使用方法记录
Aug 23 #Javascript
You might like
php发送与接收流文件的方法
2015/02/11 PHP
PHP从零开始打造自己的MVC框架之路由类实现方法分析
2019/06/03 PHP
JQuery 选择器、过滤器介绍
2011/02/14 Javascript
nodejs入门详解(多篇文章结合)
2012/03/07 NodeJs
jQuery表单获取和失去焦点输入框提示效果的实例代码
2013/08/01 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
解决Jquery鼠标经过不停滑动的问题
2014/03/03 Javascript
HTML5 JS压缩图片并获取图片BASE64编码上传
2020/11/16 Javascript
jQuery插件echarts设置折线图中折线线条颜色和折线点颜色的方法
2017/03/03 Javascript
ES6中Proxy与Reflect实现重载(overload)的方法
2017/03/30 Javascript
详解vue-router基本使用
2017/04/18 Javascript
vue.js实现用户评论、登录、注册、及修改信息功能
2020/05/30 Javascript
ReactNative列表ListView的用法
2017/08/02 Javascript
Angular浏览器插件Batarang介绍及使用
2018/02/07 Javascript
vue+echarts实现动态绘制图表及异步加载数据的方法
2018/10/17 Javascript
在vue中利用全局路由钩子给url统一添加公共参数的例子
2019/11/01 Javascript
vue 解决兄弟组件、跨组件深层次的通信操作
2020/07/27 Javascript
Windows安装Python、pip、easy_install的方法
2017/03/05 Python
Python探索之实现一个简单的HTTP服务器
2017/10/28 Python
scrapy-redis源码分析之发送POST请求详解
2019/05/15 Python
Python Web静态服务器非堵塞模式实现方法示例
2019/11/21 Python
Tensorflow 使用pb文件保存(恢复)模型计算图和参数实例详解
2020/02/11 Python
详解torch.Tensor的4种乘法
2020/09/03 Python
Python爬虫之Selenium库的使用方法
2021/01/03 Python
森海塞尔美国官网:Sennheiser耳机与耳麦
2017/07/19 全球购物
英国乡村时尚和宠物用品专家:Pet & Country
2018/07/02 全球购物
美国打印机墨水和碳粉购物网站:QuikShip Toner
2018/08/29 全球购物
潘多拉意大利官方网上商城:网上选购PANDORA珠宝
2018/10/07 全球购物
eBay加拿大站:eBay.ca
2019/06/20 全球购物
优质的学校老师推荐信
2013/10/28 职场文书
合作意向书
2014/07/30 职场文书
MySQL Innodb关键特性之插入缓冲(insert buffer)
2021/04/08 MySQL
quickjs 封装 JavaScript 沙箱详情
2021/11/02 Javascript
GPU服务器的多用户配置方法
2022/07/07 Servers
win10蓝屏0xc0000001安全模式进不了怎么办?win10出现0xc0000001的解决方法
2022/08/05 数码科技
Springboot集成kafka高级应用实战分享
2022/08/14 Java/Android