17

如何让用户选择是否离开当前页面?

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI1NTcxOTQ1Nw%3D%3D&%3Bmid=2247489650&%3Bidx=3&%3Bsn=59d7b0feae6280a3d5a55cbfb2faffc8
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

为什么要让用户选择是否离开页面

  • 如果用户填写了很多数据此时

  • 不小心点了其他a标签或者关闭了浏览器,不做判断,那么用户数据直接丢了

梳理需求

  • 离开页面方式,被location.href,a标签,关闭浏览器或者当前tab页等...

  • 需要判断数据是否跟初始化时一致(用户有无填写表单...)

  • 用户选择离开就要继续逻辑,反之则不离开

正式开始

  • 首先要知道一个事件: onbeforeunload ,MDN的说明是:当浏览器窗口关闭或者刷新时,会触发beforeunload事件。当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新。

  • :warning::HTML规范指出在此事件中调用window.alert(),window.confirm()以及window.prompt()方法,可能会失效

实践一下

  • 在微信公众号编辑器界面,输入一部分内容后,点击关闭tab页,此时出现弹窗 3yyUNnV.png!web

  • 删除所有内容后,回归初始进入的数据,点击关闭tab页,直接就关闭了,没有出现提示 eMR3M3Z.png!web

  • 看插件显示,这个编辑器界面没有使用react和vue,应该是jq吧,测试下控制台,对的,一猜就中(小编太:ox:了,不点个关注?)

回到项目中,加入 beforeunload 事件

  • HTML文件中加入script标签

 <script type="text/javascript">
window.onbeforeunload = function () {
return "Leave this page?";
}
</script>
  • 点击关闭,或者此时输入window.location.href=  "xxx.ooo.com" 会出现
aQZ3y2A.png!web
  • 那么问题来了,如果我通过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标签就无法跳转了...

iYrm6bB.png!web
  • 此时无论怎么点击一键开启都不会有效果,那么改成return true试试

    public handlePrompt = (location: Location) => {
return true;
};

  • 一跳就过去了

QjYBfyU.png!web

问题来了,怎么判断是否需要跳转呢?

  • 参考微信公众号编辑器,如果你编辑了内容后(跟初始进入的数据不一致),而且你是通过页面内a标签跳转的,那么就出现弹窗确认)

uuUfqmi.png!web
  • 那么很简单,我们使用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 -

了方便进行探讨和交流,我为大家建立了一个读者群,一起学习,一起进步。

3u6vM3n.jpg!web

:heart:爱心三连击

1.看到这里了就点个在看支持下吧,你的 「在看」 是我创作的动力。

2.关注公众号 达达前端「每天为您分享原创或精选文章」

3.特殊阶段,带好口罩,做好个人防护。

4.添加微信【xiaoda0423】,拉你进 技术交流群 一起学习

扫码关注公众号,订阅更多精彩内容。

aQbm6nv.png!web

好文章,我 在看


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK