为什么要用vuex?
进行统一的状态管理,解决不同组件共享数据的问题。
如何使用vuex?
1.安装引入 npm install vuex --save
2.注册到vue中
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)
3.实例化vuex的store
export default new Vuex.Store({state: {},getters: {},mutations: {},actions: {},modules: {}
})
4.挂载在vue实例上
new Vue({store,render: h => h(App)
}).$mount('#app')
5.在组件中就可以通过this.$store对vuex进行操作。
state 存放初始数据
state: {count: 1 },
- 组件中去取state的值,通过this.$store.state
- 或者可以通过计算属性取得,mapState辅助函数,可以简化操作:
import {mapState} from "vuex";
computed: {...mapState({// 传字符串参数 'count' 等同于 `state => state.count`count: 'count',// 箭头函数可使代码更简练count: state => state.count,})
},
getters 对state中的数据进行初加工(派生),类似vue中的computed,进行缓存
state: {arr: [1, 2, 3, 4]},getters: {// 参数一:state 参数二:其他 getterchangeArr(state,getters) {return state.arr.map(item => item + 1)}},注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。
- 取getters中的值,通过this.$store.getters,
- 或者通过计算属性取,getters也有辅助函数mapGetters, 用法和mapState一致。
import {mapGetters} from 'vuex'
// 1、
...mapGetters(['changeCount',// ...
])
// 2、
...mapGetters({changeCount: 'changeCount'// ...
})
mutations 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation 同步修改
//定义mutation
state: {count: 1,
},
mutations: {// 参数一:state 参数二:传入额外的参数increment(state, payload) {state.count = payload.count},
},
//调用mutation
// 1、普通方式
this.$store.commit('increment', {count: 10})
// 2、对象风格的提交方式this.$store.commit({type: 'increment',count: 10
})
- 在组件中提交 Mutation
你可以在组件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
import { mapMutations } from 'vuex'
methods:{...mapMutations(['increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment', {count: 10})`]),...mapMutations({add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`}),
},
this.increment({count: 10})
this.add({count: 10})
actions action类似于mutation,不同的是action可以包含异步操作 action不能直接修改state,如果想修改state的话,需要触发mutation
//定义actionstate: {count: 0},mutations: {increment (state,payload) {state.count = payload.count }},actions: {// 第一个参数通过context(上下文环境)可以触发mutation,触发action,获取state、getter等操作// 第二个参数就是我们传递过来的参数incrementAsync(context, payload) {setTimeout(() => {context.commit('increment', payload)}, 1000);}}
//调用action
// 1、普通方式
this.$store.dispatch('incrementAsync', {count: 10})
// 以对象形式分发
this.$store.dispatch({type: 'incrementAsync',count: 10
})
在组件中提交 action
你在组件中使用 this.$store.dispatch(‘xxx’) 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):
import { mapActions } from 'vuex'
methods: {...mapActions(['incrementAsync', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment', {count: 10})`]),...mapActions({add: 'incrementAsync' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`}),
},
this.incrementAsync({count: 10})
this.add({count: 10})
modules
定义module
// index.js中手动引入modules
import app from './modules/app'
modules: {app
}
<!-- app.js -->const app = {state: {num: 10},// 默认state就是有命名空间,// 如果想给mutation和action也加上命名空间的话,这里设置模块的namespaced:truegetters: {},mutations: {changeNum(state, payload) {state.num = payload.num}},actions: {}
}export default app
调用module
// 使用命名空间
this.$store.commit("app/changeNum", {num: 10})
// 未使用
this.$store.commit("changeNum", {num: 10})
vuex持久化存储
在开发的过程中, vuex数据刷新页面会初始化。像用户信息(名字,头像,token)需要vuex中存储且需要浏览器本地存储来实现持久化存储。
安装 npm install vuex-persistedstate --save
引入 import createPersistedState from ‘vuex-persistedstate’
使用
export default new Vuex.Store({plugins: [createPersistedState(),],
// 默认存储到localStorage,如果想要存储到sessionStorage,配置如下
plugins: [ // 把vuex的数据存储到sessionStorage createPersistedState({ storage: window.sessionStorage, }), ],
// 持久化所有的state,如果想要存储指定的state,配置如下
plugins: [ // 把vuex的数据存储到sessionStorage createPersistedState({ storage: window.sessionStorage, reducer(val) { return { // 只存储state中的count count: val.count } } }), ],
})
导航守卫(路由守卫)
什么是导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
全局前置守卫
const routes = [{path: '/',name: 'home',component: HomeView},{path: '/about',name: 'about',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')}
]const router = new VueRouter({mode: 'history',base: process.env.BASE_URL,routes
})router.beforeEach((to, from,next) => {// ...// 返回 false 以取消导航return false
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收三个参数:
to: 即将要进入的目标
from: 当前导航正要离开的路由
next:next 是函数
注意:确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
router.afterEach((to, from, failure) => {// console.log(failure)console.log(to,from,failure)
})
// 它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
路由独享的守卫
你可以在路由配置上直接定义 beforeEnter 守卫:这些守卫与全局前置守卫的方法参数是一样的。
const router = new VueRouter({routes: [{path: '/about',component: About,beforeEnter: (to, from, next) => {// ...}}]
})