在项目中,关于Angular路由跳转的控制(Guard)如果基本都是基于CanActivatee
与canDeactivate
,我在文章Angular的守门员canActivate与canDeactivate有较为详细的介绍,但是最后也提到,对于浏览器的刷新和关闭,canDeactivate
并不能处理,所以还是得回归本质,直接监听浏览器事件。
一,可监听的事件的列表
学过御三家 Html
, css
, js
的人应该有耳闻W3School
,这个强大的网站同样也列出了
我们在开发过程中可能需要监听的事件列表([链接][https://www.w3school.com.cn/tags/html_ref_eventattributes.asp])。
本文的目的是监听浏览器事件,但因为浏览器的刷新和关闭会直接触发Window
事件,所以实际上我们监听的是Html
中的Window
事件。这里就只简单列出比较常用的几个事件:
事件名称 | 属性(window.x) | 触发时机 |
---|---|---|
beforeunload | onbeforeunload | 顾名思义,当用户卸载文档执行之前触发 |
unload | onunload | 当用户卸载文档执行时触发(浏览器关闭) |
load | onload | 页面加载之后立即触发 |
resize | onresize | 当浏览器窗口被调整大小时触发 |
一些使用场景:
- unload: 可以类比 onDestroy(),我们可以在里面写一些清空临时数据之类的操作;
- load:可以类比onInit(),可以执行一些初始化的函数在里面;
- resize:可以直接想到的就是界面大小变化后界面动态适配;
- beforeunload:这个可以想像成 before ngOnDestroy(),就是还没Destroy之前的操作,这也是经常用到一个事件。
二,@HostListener
我们在上面我的一篇文章写到一个场景,就是用户在编辑还未保存的情况下离开当前界面,我们需要给他个提醒,当时我们用canDeactivate
已经解决了大部分场景,但是针对浏览器刷新和关闭不能处理,所以来看看Angular
中的 Dom Event Listner
:@HostListener
官方的解释是:
Decorator that declares a DOM event to listen for, and provides a handler method to run when that event occurs.
大致意思:
- 它是个修饰器(一看带了个@);
- 它需要你传入两个参数:
- eventName: string // 监听的事件名称
- args: string[] // 事件发生时传给处理器的参数
注意,我们要传的是事件名称,不是属性,比如你要监听unload
,就应该写:
@HostListener('window:unload', [`$event`]) ... // right !
@HostListener('window.onunload', [`$event`]) ... // wrong !
@HostListener('window:onunload', [`$event`]) ... // wrong !
三,实例
还是那个场景,未保存修改刷新/关闭浏览器,弹出提示:
import {
...
HostListener,
...
} from '@angular/core';
...
@HostListern('window: beforeunload', ['$event'])
private beforeUnload(event: Event) {
if(this.form.dirty) {
event.returnValue = true; // Most important
}
}
....
来看一下代码,我已经标注了非常重要的一步,我们必须对该 event-unload
来返回一个值,以此来暂停事件的继续进行(become unload)来达到我们所预期的目的。
如果不写这一句,直接写你的代码逻辑:
...
private beforeUnload(event: Event) {
if(this.form.dirty) {
// event.returnValue = true;
return this.alertService.alert('Are you confrimed ?');
}
}
...
像这样的话,你会发现你的代码确实是执行了,但是页面同样继续执行了刷新,与我们的期望背道而驰。
提示
这个before unload
事件我们写的 returnValue = true
实际上你可以写any thing,因为他都会弹出一个基于浏览器的提示框,这个东西就不受你的ux掌控了,所以如果选择使用,请首先和你的ux确定,他/她觉得可以这样做,不然别好心却被骂了。
以上本文完结。由错误的地方或者需要讨论的地方请多多指正。