在項(xiàng)目中歧强,關(guān)于Angular路由跳轉(zhuǎn)的控制(Guard)如果基本都是基于CanActivatee
與canDeactivate
芯急,我在文章Angular的守門(mén)員canActivate與canDeactivate有較為詳細(xì)的介紹岳悟,但是最后也提到主到,對(duì)于瀏覽器的刷新和關(guān)閉河泳,canDeactivate
并不能處理伶授,所以還是得回歸本質(zhì)断序,直接監(jiān)聽(tīng)瀏覽器事件。
一糜烹,可監(jiān)聽(tīng)的事件的列表
學(xué)過(guò)御三家 Html
, css
, js
的人應(yīng)該有耳聞W3School
违诗,這個(gè)強(qiáng)大的網(wǎng)站同樣也列出了
我們?cè)陂_(kāi)發(fā)過(guò)程中可能需要監(jiān)聽(tīng)的事件列表([鏈接][https://www.w3school.com.cn/tags/html_ref_eventattributes.asp])。
本文的目的是監(jiān)聽(tīng)瀏覽器事件疮蹦,但因?yàn)闉g覽器的刷新和關(guān)閉會(huì)直接觸發(fā)Window
事件诸迟,所以實(shí)際上我們監(jiān)聽(tīng)的是Html
中的Window
事件。這里就只簡(jiǎn)單列出比較常用的幾個(gè)事件:
事件名稱(chēng) | 屬性(window.x) | 觸發(fā)時(shí)機(jī) |
---|---|---|
beforeunload | onbeforeunload | 顧名思義愕乎,當(dāng)用戶(hù)卸載文檔執(zhí)行之前觸發(fā) |
unload | onunload | 當(dāng)用戶(hù)卸載文檔執(zhí)行時(shí)觸發(fā)(瀏覽器關(guān)閉) |
load | onload | 頁(yè)面加載之后立即觸發(fā) |
resize | onresize | 當(dāng)瀏覽器窗口被調(diào)整大小時(shí)觸發(fā) |
一些使用場(chǎng)景:
- unload: 可以類(lèi)比 onDestroy()阵苇,我們可以在里面寫(xiě)一些清空臨時(shí)數(shù)據(jù)之類(lèi)的操作;
- load:可以類(lèi)比onInit()感论,可以執(zhí)行一些初始化的函數(shù)在里面慎玖;
- resize:可以直接想到的就是界面大小變化后界面動(dòng)態(tài)適配;
- beforeunload:這個(gè)可以想像成 before ngOnDestroy()笛粘,就是還沒(méi)Destroy之前的操作趁怔,這也是經(jīng)常用到一個(gè)事件湿硝。
二,@HostListener
我們?cè)谏厦嫖业囊黄恼聦?xiě)到一個(gè)場(chǎng)景润努,就是用戶(hù)在編輯還未保存的情況下離開(kāi)當(dāng)前界面关斜,我們需要給他個(gè)提醒,當(dāng)時(shí)我們用canDeactivate
已經(jīng)解決了大部分場(chǎng)景铺浇,但是針對(duì)瀏覽器刷新和關(guān)閉不能處理痢畜,所以來(lái)看看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.
大致意思:
- 它是個(gè)修飾器(一看帶了個(gè)@);
- 它需要你傳入兩個(gè)參數(shù):
- eventName: string // 監(jiān)聽(tīng)的事件名稱(chēng)
- args: string[] // 事件發(fā)生時(shí)傳給處理器的參數(shù)
注意鳍侣,我們要傳的是事件名稱(chēng)丁稀,不是屬性,比如你要監(jiān)聽(tīng)unload
倚聚,就應(yīng)該寫(xiě):
@HostListener('window:unload', [`$event`]) ... // right !
@HostListener('window.onunload', [`$event`]) ... // wrong !
@HostListener('window:onunload', [`$event`]) ... // wrong !
三线衫,實(shí)例
還是那個(gè)場(chǎng)景,未保存修改刷新/關(guān)閉瀏覽器惑折,彈出提示:
import {
...
HostListener,
...
} from '@angular/core';
...
@HostListener('window:beforeunload', ['$event'])
private beforeUnload(event: Event) {
if(this.form.dirty) {
event.preventDefault();
event.returnValue = true; // Chrome requires returnValue to be set.
}
}
....
來(lái)看一下代碼授账,我已經(jīng)標(biāo)注了非常重要的一步,我們必須對(duì)該 event-unload
來(lái)返回一個(gè)值惨驶,以此來(lái)暫停事件的繼續(xù)進(jìn)行(become unload)來(lái)達(dá)到我們所預(yù)期的目的白热。
如果不寫(xiě)這一句,直接寫(xiě)你的代碼邏輯:
...
private beforeUnload(event: Event) {
if(this.form.dirty) {
// event.preventDefault();
// event.returnValue = true;
return this.alertService.alert('Are you confrimed ?');
}
}
...
像這樣的話(huà)粗卜,你會(huì)發(fā)現(xiàn)你的代碼確實(shí)是執(zhí)行了屋确,但是頁(yè)面同樣繼續(xù)執(zhí)行了刷新,與我們的期望背道而馳续扔。
提示
這個(gè)before unload
事件我們寫(xiě)的 returnValue = true
實(shí)際上你可以寫(xiě)any thing攻臀,因?yàn)樗紩?huì)彈出一個(gè)基于瀏覽器的提示框,這個(gè)東西就不受你的ux掌控了测砂,所以如果選擇使用茵烈,請(qǐng)首先和你的ux確定,他/她覺(jué)得可以這樣做砌些,不然別好心卻被罵了呜投。
以上本文完結(jié)。由錯(cuò)誤的地方或者需要討論的地方請(qǐng)多多指正存璃。