提问人:maxshuty 提问时间:11/13/2023 最后编辑:maxshuty 更新时间:11/15/2023 访问量:53
仅在命中 Vue Router 子路由时触发 API 调用
Fire API call only when a Vue Router child route is hit
问:
我正在使用 Vue2 和 vue 路由器 3x。每当点击特定子路由时,我该如何执行存储操作,无论它是通过按钮按下还是浏览器后退/前进按钮点击?
每当命中特定子路由时,我都需要触发 API 调用。目前代码工作正常,但是,当用户按下浏览器的后退/前进按钮时,它就会中断。
这是问题的细分...
我的路由器的设置方式是这样的:
const router = new Router({
mode: 'history',
routes: [
{
path: '/browse/food/:foodId',
name: 'Food',
component: foodComp,
children: [
{
path: ':routeTitle',
name: 'FoodDescription',
component: foodDescriptionComp,
props: {
viewMode: 'TEXT',
},
},
{
path: ':routeTitle',
name: 'FoodImage',
component: foodDescriptionComp,
props: {
viewMode: 'IMAGE',
},
},
{
path: ':routeTitle/food-translation',
name: 'FoodTranslation',
component: foodTranslationComp,
},
],
},
...lotsOfOtherRoutes,
],
});
...它内置了分页功能,可以在不同的食物之间切换,即在单击“下一页”(或页码)按钮时触发,其设置如下:foodDescriptionComp
method
methods: {
switchPage(pageNumber, foodIdForPageSelection) {
this.$router.push({
name: 'FoodDescription',
params: { foodId: foodIdForPageSelection },
});
await this.loadFoodByPage({
catalogId: this.catalogId,
pageNumber,
});
}
}
如您所见,页面路由器将更新路由,然后作为单独的操作,我调用 .如上所述,这很好用,但是如果用户尝试使用他们的浏览器后退按钮,那么将永远不会调用。loadFoodByPage
loadFoodByPage
我尝试了几件事来解决这个问题:
我尝试添加并移动到 ,但是,仅在初始页面加载时点击。beforeEnter
loadFoodByPage
beforeEnter
我相信使用会起作用,但是我们的应用程序中有数百条路由,为将在每个页面上检查的特定子路由添加逻辑似乎很愚蠢。beforeEach
我试过变得非常笨拙,但下面的这个解决方案不起作用,因为它只保留了一键的历史记录 - 例如,如果我从登录页面重定向到食物 1,然后转到 2、3、4,然后我按浏览器中的后退按钮,它将返回并加载第 3 页, 然后我再次按回去,它进入登录页面。即使这种方法确实有效,它也感觉非常反模式。
// Back/Forward browser button pressed
window.onpopstate = function () {
window.location.reload();
};
答:
未经测试,但这原则上应该有效。这个想法是,这将在每次路由更改时触发,并在 URL 中设置页码。如果 URL 中没有页码,则使用 1。
methods: {
switchPage(pageNumber, foodIdForPageSelection) {
this.$router.push({
name: 'FoodDescription',
params: { foodId: foodIdForPageSelection },
query: { pageNumber }
})
},
watch:{
'$route' (to, from){
if(to.name === 'FoodDescription') {
this.loadFoodByPage({
catalogId: this.catalogId,
pageNumber: this.pageNumber ? this.pageNumber : 1,
});
}
}
},
computed: {
pageNumber: () => {
return this.$route.query.pageNumber;
}
}
}
已经尝试了一些方法来解决这个问题:
我尝试添加 beforeEnter 并将 loadFoodByPage 移动到 beforeEnter,但是,这仅在初始页面加载时被击中。
我相信使用 beforeEach 会起作用,但是我们的应用程序中有数百条路由,为将在每个页面上检查的特定子路由添加逻辑似乎很愚蠢。
是的,您可以使用 or 来实现此目的。beforeEnter
beforeEach
beforeEnter - 您已经尝试过这种方法,发现它仅适用于初始页面加载。这是因为在使用浏览器的后退按钮导航回路由时,不会重新计算。beforeEnter
beforeEach - 在输入每个路由之前执行此操作,包括使用浏览器的后退按钮导航回路由时,但您担心将此防护添加到应用程序中的所有路由的性能影响。
因此,这里一个潜在的解决方案是为您的路线使用动态模块。这样,您可以添加 以仅应用需要它的路由,而不必将其添加到每个路由中。beforeEnter
例;
// Dynamic route module
const foodDescriptionModule = {
beforeEnter: async (to, from, next) => {
// Call your API here
await store.dispatch('loadFoodByPage', {
catalogId: to.params.catalogId,
pageNumber: to.params.pageNumber,
});
next();
},
children: [
{
path: ':routeTitle',
name: 'FoodDescription',
component: foodDescriptionComp,
props: {
viewMode: 'TEXT',
},
},
{
path: ':routeTitle',
name: 'FoodImage',
component: foodDescriptionComp,
props: {
viewMode: 'IMAGE',
},
},
{
path: ':routeTitle/food-translation',
name: 'FoodTranslation',
component: foodTranslationComp,
},
],
};
// Main router configuration
const router = new Router({
mode: 'history',
routes: [
{
path: '/browse/food/:foodId',
name: 'Food',
component: foodComp,
children: [foodDescriptionModule],
},
...lotsOfOtherRoutes,
],
});
在这里,防护装置在单独的模块 () 中定义。然后,此模块将包含在主路由配置的数组中。这样,防护仅应用于 中定义的路由,而不适用于应用程序中的每个路由。beforeEnter
foodDescriptionModule
children
beforeEnter
foodDescriptionModule
请注意,这假设该操作在您的 vuex 商店中可用。如果不是这种情况,您将需要相应地调整代码。然后记得将 vuex store 导入到文件顶部的 .此解决方案应允许您在命中特定子路由时执行存储操作,无论该路由是通过按钮按下还是浏览器的后退/前进按钮命中。loadFoodByPage
import store from './store'
评论
"path" is required in a route configuration.
path
评论
foodDescriptionComp
page.to === 'myChildRoute'
loadFoodByPage