爲什麼要讓用戶選擇是否離開頁面
-
如果用戶填寫了很多數據此時
-
不小心點了其他a標籤或者關閉了瀏覽器,不做判斷,那麼用戶數據直接丟了
梳理需求
-
離開頁面方式,被location.href,a標籤,關閉瀏覽器或者當前tab頁等...
-
需要判斷數據是否跟初始化時一致(用戶有無填寫表單...)
-
用戶選擇離開就要繼續邏輯,反之則不離開
正式開始
-
首先要知道一個事件:
onbeforeunload
,MDN的說明是:當瀏覽器窗口關閉或者刷新時,會觸發beforeunload事件。當前頁面不會直接關閉,可以點擊確定按鈕關閉或刷新,也可以取消關閉或刷新。 -
⚠️:HTML規範指出在此事件中調用window.alert(),window.confirm()以及window.prompt()方法,可能會失效
實踐一下
-
在微信公衆號編輯器界面,輸入一部分內容後,點擊關閉tab頁,此時出現彈窗
-
刪除所有內容後,迴歸初始進入的數據,點擊關閉tab頁,直接就關閉了,沒有出現提示
-
看插件顯示,這個編輯器界面沒有使用react和vue,應該是jq吧,測試下控制檯,對的,一猜就中(小編太🐂了,不點個關注?)
回到項目中,加入beforeunload
事件
-
HTML文件中加入script標籤
<script type="text/javascript">
window.onbeforeunload = function () {
return "Leave this page?";
}
</script>
-
點擊關閉,或者此時輸入window.location.href=
"xxx.ooo.com"
會出現
-
那麼問題來了,如果我通過a標籤跳轉呢?
通過a標籤跳轉(+前端路由)
-
我使用的是dva/router,引入相關組件
import { Prompt } from 'dva/router';
....
render(){
return <Prompt message={this.handlePrompt} />
}
-
引入Prompt組件,並且傳入message是一個方法,看看這個方法
public handlePrompt = (location: Location) => {
return false;
};
-
那麼此時我們使用dva/router的history.push方法去跳轉前端路由,就不能跳了,因爲handlePrompt一直返回false,除非返回ture,否則這個頁面通過a標籤就無法跳轉了...
-
此時無論怎麼點擊一鍵開啓都不會有效果,那麼改成return true試試
public handlePrompt = (location: Location) => {
return true;
};
-
一跳就過去了
問題來了,怎麼判斷是否需要跳轉呢?
-
參考微信公衆號編輯器,如果你編輯了內容後(跟初始進入的數據不一致),而且你是通過頁面內a標籤跳轉的,那麼就出現彈窗確認)
-
那麼很簡單,我們使用antd的Modal組件,以及lodash的deepclone(深拷貝)、_.isEqual(value, other)執行深比較來確定兩者的值是否相等。
❝注意: isEqual這個方法支持比較 arrays, array buffers, booleans, date objects, error objects, maps, numbers, Object objects, regexes, sets, strings, symbols, 以及 typed arrays. Object 對象值比較自身的屬性,不包括繼承的和可枚舉的屬性。不支持函數和DOM節點比較。
❞
實現思路講解
-
組件初始化時候,深拷貝一份表單數據存入組件中
-
當用戶通過a標籤離開頁面時,觸發handlePrompt方法,存儲離開的目的url,此時使用isEqual比較當前的數據和組件初始化的表單數據是否一致,如果不一致則出現彈窗,讓用戶選擇是否離開
-
代碼實現:
// 處理自定義離開彈窗
handlePrompt =(location )=>{
// 如果當前的保存爲false,則彈窗提醒用戶進行保存操作
if (!this.isSave) {
this.showModalSave(location);
return false;
}
return true;
}
// 展示離開的提示的彈窗
showModalSave = location => {
this.setState({
modalVisible: true,
location,
});
}
// 點擊確認,進行頁面保存操作,和保存成功後路由的跳轉
handleSaveAuto = () => {
const { location } = this.state;
const { history } = this.props;
this.isSave = true;
this.setState({
modalVisible: false,
});
//進行保存操作的處理,這裏可以換成自己點擊確認後需要做的操作
this.handleSavePaper('save','exit',location.pathname)
}
-
離開邏輯
// 取消是的路由跳轉
gotoNewUrl(url){
const {dispatch,history } = this.props
dispatch(routerRedux.push({
pathname:url,
}));
}
// 點擊取消關閉彈窗
closeModalSave=()=>{
const { location } = this.state;
const {dispatch,history } = this.props
this.isSave = true;
this.setState({
modalVisible: false,
},()=>{
this.gotoNewUrl(location.pathname)
});
}
-
html結構
<Prompt message={this.handlePrompt}/>
<Modal
title="溫馨提示"
visible={this.state.modalVisible}
closable={false}
centered
onCancel={this.closeModalSave}
footer={null}
>
<p>即將離開當前頁面,是否保存當前修改?</p>
<div style={{textAlign:'right'}}>
<Button type='primary' onClick={this.handleSaveAuto}>保存</Button>
<Button style={{marginLeft:'20px'}} onClick={this.closeModalSave}>取消</Button>
</div>
</Modal>
- EOF -
轉載自 https://mp.weixin.qq.com/s/UnO_ByuXjtTSXDf7JEz21A
作者:前端巔峯 公號 / Peter醬