需求:在离开某个页面时需要进行弹窗的二次确认。点击弹窗的确认按钮后离开,点取消不做任何离开操作。
实现方式:在beforeRouteLeave路由钩子中做拦截操作。
一:Dialog函数调用
beforeRouteLeave(to, from, next) {
// 下面这种方式,如果不加closeOnPopstate: false, 则会出现第一次生效。但是后面再进入页面再回退就不生效的问题。原因是路由改变,dialog弹窗自动关闭了导致用户无法确认,所以看vant官方文档发现 https://vant-contrib.gitee.io/vant/v2/#/zh-CN/dialog 常见问题有写到
Dialog.confirm({
title: "标题",
message: "确定要离开此页面嘛",
closeOnPopstate: false,
})
.then(() => {
// on confirm
next();
})
.catch(() => {
// on cancel
// cancelButton回调,把当前页路由推回
// 不能使用this.$router进行路由操作,会触发beforeRouteLeave导致死循环
window.history.pushState("", "", this.currentUrl);
});
}
二:Dialog组件调用
//注意:一定要将closeOnPopstate属性设置为false,否则也不会生效。
<van-dialog
v-model="isShowDialog"
title="标题"
show-cancel-button
@confirm="handleConfirm"
:closeOnPopstate="false"
>
确定要离开此页面嘛
</van-dialog>
export default {
data(){
isConfirmClicked:false
},
methods:{
handleConfirm() {
//注意:下面2步一个都不能少。如果缺少变量,则点击确定后会触发beforeRouteLeave导致死循环,点击确认不停弹窗弹窗;如果缺少路由跳转逻辑,则会点击2次回退才会到上一级路由。第一次点击会弹窗,点击确定弹窗关闭,但是并不会到上一级路由;第二次点击浏览器回退,才会正常回到上一级路由。原因可以自己琢磨~~~
this.isConfirmClicked = true
this.$router.go(-1)
},
}
}
beforeRouteLeave(to, from, next) {
if (this.isConfirmClicked) {
next();
} else {
next(false);
this.isShowDialog = true;
}
}
上面2种方式亲测有效。关键在于closeOnPopstate属性的值一定要设置为true.否则离开了当前路由,弹窗就关闭了,导致无法再次弹窗。
一开始实现没有成功,以为是浏览器刷新机制的问题。所以也在页面写了个按钮测试,如下:
<van-cell @click="back">返回上一级</van-cell>
//忘了这里为啥要这样写,好像是因为点击浏览器回退,路由变了,但是视图没有更新,还是在当前页面。没有再次复现。。。
beforeRouteEnter(to, from, next) {
next(() => {
window.localStorage.setItem("lastRoute", from.path);
});
},
back() {
this.$router.go(-1)
// this.$router.push(window.localStorage.getItem("lastRoute"));
},
于是,想着改变浏览器默认的回退事件,像这样
mounted() {
if (window.history && window.history.pushState) {
// 向历史记录中插入了当前页
history.pushState(null, null, document.URL);
window.addEventListener("popstate", this.goBack, false);
}
},
destroyed() {
//离开这个界面之后,删除事件
window.removeEventListener("popstate", this.goBack, false);
},
goBack() {
console.log("触发返回");
//第一种方式:
this.isShowDialog = true;
//第二种方式:
// Dialog.confirm({
// title: "标题",
// message: "确定要离开此页面嘛",
// })
// .then(() => {
// // on confirm
// window.history.go(-1)
// })
// .catch(() => {
// // on cancel
// // cancelButton回调,把当前页路由推回
// // 不能使用this.$router进行路由操作,会触发beforeRouteLeave导致死循环
// window.history.pushState("", "", this.currentUrl);
// });
},
下面这种方式哪怕不设置弹窗的closeOnPopstate属性也能生效。思考下是为什么把?
补充: vue监听浏览器原生返回按钮,进行路由转跳操作。注意不能直接在beforeRouteLeave中调用this.$router.psuh()方法,否则页面会进入死循环! www.yii666.com/blog/236119…