在Vue中,每隔一段时间,您就会希望防止用户改变路由或重新加载页面。例如,他们可能在没有保存的情况下对表单进行了更改。
这种行为我们避免不了,但通过技术阻止用户操作(例如刷新等)来说还是很容易实现的。
首先,我们需要一些条件来跟踪用户是否可以导航离开。但在这个例子中,我们会用一个布尔值来跟踪用户是否在编辑东西(下文的的例子在你的代码中实现可能不同,具体代码根据自身业务处理)
<script>
export default {
data: () => ({
isEditing: false
})
</script>
防止URL更改和/或页面重新加载
接下来,我们需要添加一些逻辑,以防止用户跳转到新的URL,或在isEditing标志为true时重新加载页面。
幸运的是,浏览器有一个本地beforeunload事件。
把它添加到beforeMount钩子中,这样就知道我们不是在一个服务器渲染的环境中:
<script>
export default {
// ...
beforeMount() {
window.addEventListener("beforeunload", event => {
if (!this.isEditing) return
event.preventDefault()
// Chrome requires returnValue to be set.
event.returnValue = ""
})
}
}
</script>
Vue在自动删除添加到模板中的任何事件处理程序方面做得很好,但是我们手工创建的任何事件处理程序都应该被清除,以避免任何内存泄漏。
为此,我们将匿名函数重构为一个命名方法,以便在beforeDestroy钩子中清理它:
<script>
export default {
// ...
beforeMount() {
window.addEventListener("beforeunload", this.preventNav)
},
beforeDestroy() {
window.removeEventListener("beforeunload", this.preventNav);
},
methods: {
preventNav(event) {
if (!this.isEditing) return
event.preventDefault()
event.returnValue = ""
}
}
}
</script>
如果愿意,还可以使用Vue的方法将事件侦听器逻辑组合在一起:
<script>
export default {
// ...
beforeMount() {
window.addEventListener("beforeunload", this.preventNav)
this.$once("hook:beforeDestroy", () => {
window.removeEventListener("beforeunload", this.preventNav);
})
},
methods: {
preventNav(event) {
if (!this.isEditing) return
event.preventDefault()
event.returnValue = ""
}
}
}
</script>
防止路由器跳转
太棒了!到目前为止,我们的组件将防止用户在浏览器发生更改时意外丢失更改,但您的路由更改实际上可能是由JavaScript处理的。如果是这种情况,还需要防止Vue路由器导航离开。
为此,我们可以方便地在beforeRouteLeave之前挂钩到组件内的导航保护(假设你正在使用)。
顾名思义,在您准备离开当前路由时运行beforeoutleave。它为我们提供了一些参数:
- to:准备跳转(到)的路由对象
- from:离开(当前)的路由对象
- next:用于调用导航的函数。你也可以使用它来跳转到任何其他你喜欢的路由
就我们的目的而言,我们只对next参数感兴趣,我们可以将其与检查相结合,询问用户是否想要继续导航:
<script>
export default {
// ...
beforeRouteLeave(to, from, next) {
if (this.isEditing) {
if (!window.confirm("Leave without saving?")) {
return;
}
}
next();
}
}
</script>
结束语
这样,我们就有了一个漂亮的小组件,它可以防止用户根据我们的逻辑进行导航。当然,我们实际上并没有实现任何逻辑,因为我将把它留给您来处理。
整个过程是这样的:
<script>
export default {
data: () => ({
isEditing: false
}),
beforeMount() {
window.addEventListener("beforeunload", this.preventNav)
this.$once("hook:beforeDestroy", () => {
window.removeEventListener("beforeunload", this.preventNav);
})
},
beforeRouteLeave(to, from, next) {
if (this.isEditing) {
if (!window.confirm("Leave without saving?")) {
return;
}
}
next();
},
methods: {
preventNav(event) {
if (!this.isEditing) return
event.preventDefault()
event.returnValue = ""
},
},
}
</script>
你可以在这里看到一个Demo示例(翻墙):
如果需要,你可以将它做成mixin。