什么是vuex?
官方: Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
工作流程:
用户通过dispatch去分发actions,再通过commit提交mutation去改变state,伴随state的改变重新渲染组件。
注意:
用户可以直接通过this.$store.commit提交mutations。
为什么需要通过dispatch触发actions,再通过commit提交mutation呢?
因为mutations支持同步;actions支持异步操作,往往用户在操作数据时,需要调用后端接口是异步的操作,所以一般都是通过actions再mutations。
Vuex环境配置
一、安装 npm i vuex
注意: 安装时不指定版本,会安装最新版本。vuex的4版本,只能在vue3中使用,项目是vue2的要安装4版本以下的vuex版本。
//在根目录新建store文件->store.js,进行如下配置
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//对外暴露store类的一个实例
export default new Vuex.Store({
state: {},
actions: {},
mutations: {},
getters: {},
})
三、在main.js中引入配置的store文件下的js文件
import Vue from 'vue'
import App from './App.vue'
//引入store文件
import store from './store/store.js'
Vue.config.productionTip = false
new Vue({
store, //注册
render:h=>h(App)
}).$mount('#app')
核心概念
State
提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,与data相似。
使用state
直接在标签中使用
<div>{{$store.state.lyc}}</div>
从vuex中按需导入mapstate函数,然后映射到computed中
import { mapState } from "vuex"
...mapState({'lyc':'lyc'})
//组件中的新名称和vuex中的原名称一样就可以
//mapState、mapGetters、mapMutations、mapActions都可以这样使用
...mapState(["lyc"])
//映射后
<div>{{lyc}}</div>
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
使用mutations
注意:在 mutations 里写的必须是同步函数
mutations: {
abc(state) {
//对state中数据的操作
}
}
直接使用commit提交Mutation
this.$store.commit("abc")
从vuex中按需导入mutation函数,然后映射到methods方法中
import { mapMutations } from "vuex"
...mapMutations(['abc'])
Action
接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。
使用actions
Action 提交的是 mutation,而不是直接变更状态
Action和Mutation相似,Mutation 不能进行异步操作,若要进行异步操作,就得使用Action。
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
直接使用 dispatch分发Action
this.$store.dispatch("incrementAsync")
从vuex中按需导入action函数,然后映射到methods方法中
import { mapActions } from "vuex"
...mapActions(['incrementAsync'])
就可以直接使用这个方法
this.incrementAsync
Getter
对于Store中的数据进行加工处理形成新的数据,接受 state 作为其第一个参数。
注意:vue2时类似于vue中的computed,进行缓存;vue3中getter 的结果不再像计算属性一样会被缓存起来。
使用getters
直接在标签中使用
<div>{{$store.getter.lyc}}</div>
从vuex中按需导入getter函数,然后映射到计算属性computed中
import { mapGetters } from "vuex"
...mapGetters(['lyc'])
//映射后
<div>{{lyc}}</div>
Vuex允许我们将store分割成模块(module)
默认情况下,模块内部的 getter、action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 getter、action 或 mutation 作出响应,也就是分割出的模块这三个属性也是公用的,为了不出现模块中同一属性的错误,我们需要在模块中开启命名空间(namespaced: true),开启命名空间的模块,不会被其他模块的同一属性影响。
例子:
store.js文件 其他两个都是模块文件
//导入 Vue 和 Vuex
import Vue from 'vue'
import Vuex from 'vuex'
//将 Vuex 安装为 Vue 的插件
Vue.use(Vuex)
//导入购物车的 vuex 模块
import moduleCart from './cart.js'
//导入用户的 vuex 模块
import moduleUser from './user.js'
//对外暴露store类的一个实例
export default new Vuex.Store({
// 挂载 store 模块
modules: {
// 挂载到购物车的 vuex 模块,模块内成员的访问路径被调整为 m_cart
'm_cart': moduleCart, //就是把导入的模块,改个名
//挂载用户的 vuex 模块,访问路径为 m_user
'm_user': moduleUser
},
})
user.js
//对于模块内部的 mutation 和 getter,接收的第一个参数是state
export default {
//开启命名空间
namespaced: true,
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
//这个对模块中actions的描述是没有可以,可以去官方看
当使用多个模块时,映射方法就需要改一下
当多个模块,当前组件引入同一个模块中的属性时
mapState、mapGetters、mapMutations、mapActions第一个参数时字符串(模块名称),
第二个参数是数组(组件中的新名称和vuex中的原名称一样),或者对象(就是需要重命名时)
mapXXXs('模块名',['属性名1','属性名2'])
mapXXXs('模块名',{
'组件中新名称1':'Vuex中原名称1',
'组件中新名称2':'Vuex中原名称2'
})
当多个模块,当前组件引入不同模块中同属性时
computed:{
...mapState({
'组件新名称': state => state.模块名1.'Vuex中原名称',
'组件新名称': state => state.模块名2.'Vuex中原名称',
})
}
methods:{
...mapMutations({
'组件新名称':"模块名1/Vuex中原名称",
'组件新名称':"模块名2/Vuex中原名称",
}),
...mapActions({
'组件新名称':"模块名1/Vuex中原名称",
'组件新名称':"模块名2/Vuex中原名称",
})
}
Vuex面试题
1、vuex如何实现数据持久化
答:因为vuex中的state是存储在内存中的,一刷新就没了,例如登录状态,解决方案有:
第一种:利用本地存储(localStorage,sessionStorage)
state:{
//本地缓存有就拿本地缓存的
num:localStorage.getItem('num') || 1
},
mutations:{
add(state){
state.num++;
//把数据存到本地缓存
localStorage.setItem('num',state.num)
}
}
第二种:利用第三方封装好的插件,例如:vuex-persistedstate
2、在某个组件中可以直接修改Vuex的状态(数据)吗?
可以的:
1、通过mutataions方法来修改
2、this.$store.state.xxx可以直接修改源头数据;使用辅助函数(...mapxxx)this.xxx是不可以修改的。因为mapState会把state的某一值复制一份给当前组件对象,这个跟data中return的数据处理一样。
3、Vuex中getters属性在组件中被v-model绑定会发生什么?
Vuex是单向数据流,所以v-model绑定getters会报错,而且没有get和set写法(组件的计算属性有)
4、mutations和actions的区别
1、Actions提交的是mutations,而不是直接变更状态。
actions可以直接修改state属性值? 可以,但是不建议这样写
2、mutations是同步函数,actions可以包含异步
面试中回答:actions可以包含异步操作,mutations必须是同步的,actions直接提交mutations,通过mutations去修改state的状态。
vuex官方文档 Vuex 是什么? | Vuex