Javascript 定义Vue路由器路由时访问Vuex状态
我有以下Vuex商店(main.js):Javascript 定义Vue路由器路由时访问Vuex状态,javascript,vue.js,vuejs2,vue-router,vuex,Javascript,Vue.js,Vuejs2,Vue Router,Vuex,我有以下Vuex商店(main.js): 从“Vue”导入Vue 从“Vuex”导入Vuex Vue.use(Vuex) //初始化存储 const store=新的Vuex.store({ 声明:{ 全局错误:“”, 用户:{ 认证:假 } }, 突变:{ setGlobalError(状态,错误){ state.globalError=错误 } } }) //初始化应用程序 const app=新的Vue({ 路由器:路由器,, 商店, 模板:“”, 组件:{App} }).$mount(“
从“Vue”导入Vue
从“Vuex”导入Vuex
Vue.use(Vuex)
//初始化存储
const store=新的Vuex.store({
声明:{
全局错误:“”,
用户:{
认证:假
}
},
突变:{
setGlobalError(状态,错误){
state.globalError=错误
}
}
})
//初始化应用程序
const app=新的Vue({
路由器:路由器,,
商店,
模板:“”,
组件:{App}
}).$mount(“#应用程序”)
我还为Vue路由器定义了以下路由(routes.js):
从“Vue”导入Vue
从“vue路由器”导入VueRouter
Vue.use(VueRouter)
//定义路线
常数路由=[
{路径:'/home',名称:'home',组件:home},
{路径:'/login',名称:'login',组件:login},
{路径:'/secret',名称:'secret',组件:SecretPage,元:{requiresLogin:true}
]
我试图这样做,如果Vuex存储了用户
对象,并且将已验证的
属性设置为false
,则路由器会将用户重定向到登录页面
我有这个:
Router.beforeach((to,from,next)=>{
if(to.matched.some(record=>record.meta.requiresLogin)&&&{
//设置Vuex状态的全局错误,然后重定向
下一步(“/Login”)
}否则{
下一个()
}
})
问题是我不知道如何从beforeach
函数中访问Vuex商店的user
对象
我知道我可以在组件内部使用BeforeRouteEnter
,但这会使每个组件变得混乱。我想在路由器级别集中定义它。正如建议的那样,您可以做的是从存储所在的文件导出存储,并将其导入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
现在在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()
}
})
在main.js中还可以导入存储
:
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')
从“Vue”导入Vue
从“Vuex”导入Vuex
Vue.use(Vuex)
从“./store.js”导入存储
//初始化应用程序
const app=新的Vue({
路由器:路由器,,
商店,
模板:“”,
组件:{App}
}).$mount(“#应用程序”)
我最终将存储从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()
}
})
这就是我要做的 在App.vue中,我将在存储身份验证详细信息的cookie上保留一个监视程序。(显然,我会在身份验证后将包含身份验证详细信息的令牌存储为cookie)
现在,每当此cookie变为空时,我都会将用户路由到/login页。注销会删除cookie。现在,如果用户在注销后回击,现在因为cookie不存在,(这需要用户登录),用户将被路由到登录页。将您的位置状态与应用程序的其他状态分开管理可能会使类似的事情变得更加困难。在处理了Redux和Vuex中的类似问题后,我开始在Vuex存储中使用
路由器
模块来管理我的位置状态。您可能需要我不想考虑使用那种方法
在您的特定情况下,您可以观察Vuex存储本身内的位置何时发生变化,并发送适当的“重定向”操作,如下所示:
dispatch("router/push", {path: "/login"})
将位置状态作为Vuex模块进行管理比您想象的要简单。如果您想尝试,可以使用我的作为起点:
我发现在使用guard router.beforeach时,router.py中的存储区不可用,但是通过更改 防护路由器。在解决之前,存储可用 我还发现,通过在guard router.beforeach中等待存储的导入,我就能够成功地使用router.beforeach。我在router.beforeach代码下面提供了一个示例 因此,为了使我的示例与OP的问题保持一致,以下是它对我的作用。我使用的是vue路由器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;
我还发现,我可以通过在beforeach守卫中等待存储加载来让router.beforeach工作
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
});
以@Saurabh建议的方式导入商店是可行的。但是,它给代码带来了某种解决方法的味道 它是有效的,因为Vuex存储是一个单例。导入它会在组件、路由器和存储之间创建一个硬链接的依赖关系。至少它会使单元测试变得更困难。vue路由器是解耦的,并且这样工作是有原因的,遵循其建议的模式并保持路由器解耦可能会有回报从实际的商店实例开始 查看vue路由器的来源,很明显,有一种更优雅的方式可以从路由器访问存储,例如在
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
})
}
编辑日期:2020年9月10日(感谢@Andi指出这一点)
使用beforeRouteEnter
防护装置,然后根据具体情况进行操作。在bat之外,我可以看到以下选项:
Vue.use(VueRouter)之后声明;
:和)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' });
})
这是一个问题。我通过使用解决了这个问题。
这将在本地存储中保存vuex状态
在你的店里
import createPersistedState from "vuex-persistedstate";
const store = new Vuex.Store({
plugins: [createPersistedState()],
state: {
user: null,
// ...
},
mutations: {// ...},
actions: {// ...},
getters: {// ...}
});