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

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

  • 如果用戶填寫了很多數據此時

  • 不小心點了其他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醬

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章