MST

星途 面试题库

面试题:Vue Router跨版本中路由守卫的兼容性与迁移

Vue Router不同版本间路由守卫的使用存在一些差异,比如2.x到4.x版本。请详细描述路由守卫在跨版本过程中的兼容性问题,以及在实际项目迁移时,如何针对全局守卫、路由独享守卫和组件内守卫进行正确的迁移和调整。
39.5万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

路由守卫跨版本兼容性问题

  1. 语法变化:Vue Router 2.x 到 4.x 版本,部分守卫的语法发生了改变。例如在 2.x 中,全局前置守卫使用 router.beforeEach,语法为 router.beforeEach((to, from, next) => { /*... */ });在 4.x 中,同样是全局前置守卫,使用 router.beforeEach((to, from) => { /*... */ return true | false | Promise }),不再接收 next 函数,而是通过返回值控制导航行为。
  2. 守卫参数变化:4.x 版本中部分守卫的参数结构有调整。以全局解析守卫为例,2.x 中为 router.beforeResolve((to, from, next) => { /*... */ }),4.x 为 router.beforeResolve((to, from) => { /*... */ return true | false | Promise }),参数数量和控制方式改变。
  3. 生命周期钩子变化:组件内守卫在 4.x 中,beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave 这些钩子函数的上下文(this)获取方式有所不同。2.x 中可以在 next 回调函数中访问组件实例,如 beforeRouteEnter(to, from, next) { next(vm => { /* 访问 vm 实例 */ }) };4.x 中需要使用 onBeforeRouteEnter 等组合式 API,在 setup 函数中通过 getCurrentInstance 获取实例,如 import { onBeforeRouteEnter } from 'vue-router'; onBeforeRouteEnter((to, from) => { const { proxy } = getCurrentInstance(); /* 通过 proxy 访问实例 */ })

实际项目迁移时的调整

  1. 全局守卫迁移
    • 全局前置守卫:2.x 代码:
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
const router = new Router({ /*... */ });
router.beforeEach((to, from, next) => {
    if (to.meta.requiresAuth &&!isAuthenticated()) {
        next('/login');
    } else {
        next();
    }
});
export default router;

4.x 代码:

import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
    history: createWebHistory(),
    routes: []
});
router.beforeEach((to, from) => {
    if (to.meta.requiresAuth &&!isAuthenticated()) {
        return '/login';
    }
    return true;
});
export default router;
- **全局解析守卫**:2.x 代码:
router.beforeResolve((to, from, next) => {
    if (to.meta.requiresData) {
        fetchData(to).then(() => {
            next();
        }).catch((error) => {
            next({ name: 'Error', params: { error } });
        });
    } else {
        next();
    }
});

4.x 代码:

router.beforeResolve(async (to, from) => {
    if (to.meta.requiresData) {
        try {
            await fetchData(to);
            return true;
        } catch (error) {
            return { name: 'Error', params: { error } };
        }
    }
    return true;
});
- **全局后置钩子**:2.x 中是 `router.afterEach((to, from) => { /*... */ })`;4.x 同样是 `router.afterEach((to, from) => { /*... */ })`,语法基本不变,但 4.x 中不再支持第三个参数 `failure`。

2. 路由独享守卫迁移 - 2.x 代码:

const routes = [
    {
        path: '/protected',
        name: 'Protected',
        component: ProtectedComponent,
        beforeEnter: (to, from, next) => {
            if (!isAuthenticated()) {
                next('/login');
            } else {
                next();
            }
        }
    }
];
- 4.x 代码:
const routes = [
    {
        path: '/protected',
        name: 'Protected',
        component: ProtectedComponent,
        beforeEnter: (to, from) => {
            if (!isAuthenticated()) {
                return '/login';
            }
            return true;
        }
    }
];
  1. 组件内守卫迁移
    • beforeRouteEnter:2.x 代码:
export default {
    data() {
        return { /*... */ };
    },
    beforeRouteEnter(to, from, next) {
        if (to.params.id) {
            next();
        } else {
            next({ name: 'NotFound' });
        }
    }
};

4.x 代码:

import { onBeforeRouteEnter } from 'vue-router';
export default {
    setup() {
        onBeforeRouteEnter((to, from) => {
            if (to.params.id) {
                return true;
            }
            return { name: 'NotFound' };
        });
    }
};
- **beforeRouteUpdate**:2.x 代码:
export default {
    data() {
        return { /*... */ };
    },
    beforeRouteUpdate(to, from, next) {
        this.fetchData(to);
        next();
    }
};

4.x 代码:

import { onBeforeRouteUpdate } from 'vue-router';
export default {
    setup() {
        const fetchData = (to) => { /*... */ };
        onBeforeRouteUpdate((to, from) => {
            fetchData(to);
            return true;
        });
    }
};
- **beforeRouteLeave**:2.x 代码:
export default {
    data() {
        return { /*... */ };
    },
    beforeRouteLeave(to, from, next) {
        if (this.hasUnsavedChanges) {
            next(false);
        } else {
            next();
        }
    }
};

4.x 代码:

import { onBeforeRouteLeave } from 'vue-router';
export default {
    setup() {
        const hasUnsavedChanges = ref(false);
        onBeforeRouteLeave((to, from) => {
            if (hasUnsavedChanges.value) {
                return false;
            }
            return true;
        });
    }
};