Ege*_*soz 26 javascript vue.js vue-router vuex vuejs2
我有以下Vuex商店(main.js):
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//init store
const store = new Vuex.Store({
state: {
globalError: '',
user: {
authenticated: false
}
},
mutations: {
setGlobalError (state, error) {
state.globalError = error
}
}
})
//init app
const app = new Vue({
router: Router,
store,
template: '<app></app>',
components: { App }
}).$mount('#app')
Run Code Online (Sandbox Code Playgroud)
我还为Vue-Router(routes.js)定义了以下路由:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//define routes
const routes = [
{ path: '/home', name: 'Home', component: Home },
{ path: '/login', name: 'Login', component: Login },
{ path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]
Run Code Online (Sandbox Code Playgroud)
我试图这样做,如果Vuex商店的user对象具有authenticated属性false,请让路由器将用户重定向到Login页面.
我有这个:
Router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLogin) && ???) {
// set Vuex state's globalError, then redirect
next("/Login")
} else {
next()
}
})
Run Code Online (Sandbox Code Playgroud)
问题是我不知道如何user从beforeEach函数中访问Vuex商店的对象.
我知道我可以在组件内部使用路由器保护逻辑BeforeRouteEnter,但这会使每个组件混乱.我想在路由器级别集中定义它.
Sau*_*abh 37
正如这里建议的那样,您可以做的是从您所在的文件中导出您的商店并将其导入routes.js.它将类似于以下内容:
你有一个store.js:
import Vuex from 'vuex'
//init store
const store = new Vuex.Store({
state: {
globalError: '',
user: {
authenticated: false
}
},
mutations: {
setGlobalError (state, error) {
state.globalError = error
}
}
})
export default store
Run Code Online (Sandbox Code Playgroud)
现在在routes.js中,您可以:
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from ./store.js
Vue.use(VueRouter)
//define routes
const routes = [
{ path: '/home', name: 'Home', component: Home },
{ path: '/login', name: 'Login', component: Login },
{ path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]
Router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLogin) && ???) {
// You can use store variable here to access globalError or commit mutation
next("/Login")
} else {
next()
}
})
Run Code Online (Sandbox Code Playgroud)
在main.js中你也可以导入store:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import store from './store.js'
//init app
const app = new Vue({
router: Router,
store,
template: '<app></app>',
components: { App }
}).$mount('#app')
Run Code Online (Sandbox Code Playgroud)
我最终将 store 从 main.js 移到 store/index.js,并将其导入到 router.js 文件中:
import store from './store'
//routes
const routes = [
{ path: '/home', name: 'Home', component: Home },
{ path: '/login', name: 'Login', component: Login },
{ path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]
//guard clause
Router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLogin) && store.state.user.authenticated == false) {
store.commit("setGlobalError", "You need to log in before you can perform this action.")
next("/Login")
} else {
next()
}
})
Run Code Online (Sandbox Code Playgroud)
您可以使用router.app访问路由器注入的根 Vue 实例,然后通过router.app.$store.
const router = new Router({
routes,
})
router.beforeEach((to, from, next) => {
// access store via `router.app.$store` here.
if (router.app.$store.getters('user')) next();
else next({ name: 'login' });
})
Run Code Online (Sandbox Code Playgroud)
这是API 参考。
将您的位置状态与应用程序状态的其余部分分开管理可能会使这样的事情比他们可能需要的更难。处理在这两个终极版和Vuex类似问题后,我开始管理我的位置状态里面我Vuex店,使用router模块。您可能想考虑使用这种方法。
在您的特定情况下,您可以观察 Vuex 存储本身内的位置何时发生变化,并分派适当的“重定向”操作,如下所示:
dispatch("router/push", {path: "/login"})
Run Code Online (Sandbox Code Playgroud)
将位置状态作为 Vuex 模块进行管理比您想象的要容易。如果您想尝试一下,可以使用我的作为起点:
https://github.com/geekytime/vuex-router
按照@Saurabh 建议的方式导入商店。但是恕我直言,它给您的代码带来了某种解决方法的味道。
它有效,因为 Vuex 商店是一个单例。导入它会在你的组件、路由器和商店之间创建一个硬链接依赖。至少它使单元测试变得更加困难。vue-router 被解耦并像这样工作是有原因的,遵循其建议的模式并保持路由器与实际商店实例解耦可能会有回报。
查看 vue-router 的源代码,很明显有一种更优雅的方式可以从路由器访问商店,例如在beforeRouteEnter守卫中:
beforeRouteEnter: (to, from, next) => {
next(vm => {
// access any getter/action here via vm.$store
// avoid importing the store singleton and thus creating hard dependencies
})
}
Run Code Online (Sandbox Code Playgroud)
2020 年 9 月 10 日编辑(感谢 @Andi 指出这一点)
beforeRouteEnter然后根据具体情况使用防护装置。我立即看到以下选项:
Vue.use(VueRouter);: here和here之后声明)我发现在使用保护 router.beforeEach 时,我在 router.py 中无法使用该商店,但是通过将保护更改为 router.beforeResolve,然后该商店可用。
我还发现,通过在守卫 router.beforeEach 中等待 store 的导入,我就能够成功地使用 router.beforeEach。我在 router.beforeResolve 代码下面提供了一个例子。
因此,为了使我的示例与 OP 的问题相似,以下是它对我的工作方式。我正在使用 vue-router 3.0.2 和 vuex 3.1.0。
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store'; //or use a full path to ./store
Vue.use(VueRouter)
//define routes
const routes = [
{ path: '/home', name: 'Home', component: Home },
{ path: '/login', name: 'Login', component: Login },
{ path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]
const router = new VueRouter({
routes //es6
})
router.beforeResolve((to, from, next) => {
const user = store.state.user.user; //store with namespaced modules
if (to.matched.some(record => record.meta.requiresLogin) && user.isLoggedIn) {
next() //proceed to the route
} else next("/login") //redirect to login
})
export default router;
Run Code Online (Sandbox Code Playgroud)
我还发现我可以通过在 beforeEach 守卫中等待商店的加载来让 router.beforeEach 工作。
router.beforeEach(async (to, from, next) => {
const store = await import('@/store'); //await the store
const user = store.state.user.user; //store with namespaced modules
if (to.matched.some(record => record.meta.requiresLogin) && user.isLoggedIn) {
.... //and continue as above
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30137 次 |
| 最近记录: |