面试题答案
一键面试路由守卫跨版本兼容性问题
- 语法变化: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
函数,而是通过返回值控制导航行为。 - 守卫参数变化:4.x 版本中部分守卫的参数结构有调整。以全局解析守卫为例,2.x 中为
router.beforeResolve((to, from, next) => { /*... */ })
,4.x 为router.beforeResolve((to, from) => { /*... */ return true | false | Promise })
,参数数量和控制方式改变。 - 生命周期钩子变化:组件内守卫在 4.x 中,
beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
这些钩子函数的上下文(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 访问实例 */ })
。
实际项目迁移时的调整
- 全局守卫迁移
- 全局前置守卫: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;
}
}
];
- 组件内守卫迁移
- 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;
});
}
};