Vue3中onBeforeRouteLeave无法等待用户输入的解决问询
解决方案
你的问题核心有两个:一是组合式API中错误使用了this,二是用轮询监听用户输入的方式不可靠且无效。以下是修正后的完整实现:
1. 修正响应式变量与模板逻辑
首先确保所有弹窗相关变量都是ref声明的响应式变量,同时修改按钮点击事件,直接关联Promise的状态变更:
模板部分
<q-dialog v-model="unsaveGridDialog" persistent> <q-card> <q-card-section class="row items-center"> <q-avatar icon="save" color="primary" text-color="white" /> <span class="q-ml-sm">是否要在未保存网格的情况下离开页面?</span> </q-card-section> <q-card-actions align="right"> <q-btn @click="handleCancel" flat label="取消" color="primary" v-close-popup /> <q-btn @click="handleConfirm" flat label="确认离开" color="primary" v-close-popup /> </q-card-actions> </q-card> </q-dialog>
2. 重构脚本逻辑
响应式变量声明
import { ref, onBeforeRouteLeave } from 'vue'; const unsaveGridDialog = ref(false); // 保存Promise的resolve/reject引用,由按钮点击触发状态变更 let resolveLeavePromise = null; let rejectLeavePromise = null; // 假设这是你判断是否有未保存更改的变量 const hasUnsavedChanges = ref(false);
弹窗与路由守卫逻辑
function showUnsaveDialog() { unsaveGridDialog.value = true; return new Promise((resolve, reject) => { resolveLeavePromise = resolve; rejectLeavePromise = reject; }); } function handleConfirm() { resolveLeavePromise?.(); resetDialogState(); } function handleCancel() { rejectLeavePromise?.(); resetDialogState(); } function resetDialogState() { unsaveGridDialog.value = false; resolveLeavePromise = null; rejectLeavePromise = null; } // 路由守卫 onBeforeRouteLeave((to, from, next) => { if (hasUnsavedChanges.value) { showUnsaveDialog() .then(() => next()) // 用户确认,允许路由跳转 .catch(() => next(false)); // 用户取消,阻止路由跳转 } else { next(); // 无未保存更改,直接跳转 } });
问题原理解释
this的错误使用:在Vue3组合式API中,this指向undefined,你原来的this.unsaveConfirm无法获取到响应式变量的值,导致轮询永远不会触发resolve或reject。- 轮询的低效与不可靠:通过
setTimeout轮询监听变量状态是不必要的,直接通过用户点击事件触发Promise状态变更才是正确的异步交互方式。 - 状态重置:每次弹窗关闭后重置Promise引用,避免后续弹窗出现逻辑混乱。
内容的提问来源于stack exchange,提问作者Tadeas Vasko
相关产品推荐
相关产品推荐

