如何讓用戶選擇是否離開當前頁面?

寫在開頭

  • 爲何要寫這個文章,由於每一個禮拜都有人問我這個問題...
  • 抄一個微信公衆號的編輯器的相似功能場景來實現

爲何要讓用戶選擇是否離開頁面

  • 若是用戶填寫了不少數據此時
  • 不當心點了其餘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節點比較。javascript

html

實現思路講解

  • 組件初始化時候,深拷貝一份表單數據存入組件中
  • 當用戶經過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>`

結束語

  • 遇到問題時候,應該先搜索引擎一波,準確的來講,你的月薪在50K如下,都應該多考慮使用別人的輪子/改造別人的輪子,前端發展到如今已經技術基本穩定(實現業務邏輯層面),前人也留下了不少寶貴經驗,遇到問題,必定要先百度或者谷歌
  • 感受對你有幫助,能夠右下角點個在看,關注一波公衆號:[前端巔峯]
  • 另外歡迎收藏個人資料網站:前端生活社區:https://qianduan.life
相關文章
相關標籤/搜索