You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MobX Router过渡钩子中检测浏览器前进/后退触发的路由变化?

如何区分路由变化是浏览器按钮触发还是代码调用routerStore.goTo()触发?

假设我们有以下两个路由配置:

viewRoute = {
    name: "View Route",
    pattern: "/route/view"
}

editRoute = {
    name: "Edit Route",
    pattern: "/route/edit",
    beforeExit: (fromState, toState, routerStore) => {
        if (/* 路由变化由浏览器按钮触发 */) {
            if (confirm("Do you want to discard changes?")) {
                return toState;
            } else {
                return fromState;
            }
        }
    }
}

需求是:用户点击“取消”/“保存”按钮调用routerStore.goTo()跳转时不弹确认框,通过浏览器前进/后退按钮跳转时才弹出确认框。下面提供两种可行的实现思路:

方案一:给代码触发的跳转添加自定义标记

这种方法直接在代码跳转时传递一个自定义参数,在beforeExit钩子中检查该参数来判断跳转来源,是最可靠的方案。

  1. 修改按钮的跳转逻辑,添加自定义参数:
// 取消按钮或保存按钮的跳转代码
routerStore.goTo(viewRoute, { skipConfirm: true });
  1. 在beforeExit钩子中判断标记:
editRoute = {
    name: "Edit Route",
    pattern: "/route/edit",
    beforeExit: (fromState, toState, routerStore) => {
        // 检查目标路由的参数中是否带有skipConfirm标记
        const isCodeTriggered = toState?.params?.skipConfirm === true;
        if (!isCodeTriggered) {
            // 无标记则判定为浏览器按钮触发的跳转
            if (confirm("Do you want to discard changes?")) {
                return toState;
            } else {
                return fromState;
            }
        }
        // 代码触发的跳转,直接放行
        return toState;
    }
}

方案二:通过popstate事件标记浏览器导航

浏览器的前进/后退按钮会触发popstate事件,而代码调用routerStore.goTo()一般不会触发该事件(除非手动调用pushState/replaceState)。我们可以通过全局变量标记跳转来源:

  1. 全局定义标记变量并监听popstate事件:
let isBrowserNavigation = false;

window.addEventListener('popstate', () => {
    isBrowserNavigation = true;
});
  1. 修改代码跳转的逻辑,重置标记:
// 取消/保存按钮的跳转函数
function handleNavigateToView() {
    isBrowserNavigation = false;
    routerStore.goTo(viewRoute);
}
  1. 在beforeExit钩子中判断标记,并及时重置:
editRoute = {
    name: "Edit Route",
    pattern: "/route/edit",
    beforeExit: (fromState, toState, routerStore) => {
        if (isBrowserNavigation) {
            if (confirm("Do you want to discard changes?")) {
                // 跳转成功后重置标记,避免影响后续跳转
                isBrowserNavigation = false;
                return toState;
            } else {
                isBrowserNavigation = false;
                return fromState;
            }
        }
        return toState;
    }
}

注意:如果你的路由库在处理代码跳转时也会触发popstate,需要在路由跳转完成的钩子(比如afterEnter)中主动重置isBrowserNavigation为false,避免误判。

内容的提问来源于stack exchange,提问作者sookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 14:51:23