VUEX
状态管理,多个组件有共享数据的时候,就叫状态管理
什么情况下会用到vuex , 如果你不知道vuex的情况也能完成你的需求,就说你的项目中不需要用到状态管理。
组件层级比较复杂的时候,还是用组件传值的方式来传值,那么就会很不方便,给我们的开发造成一些不必要的麻烦,使用了vuex之后,提供统一的api, 管理起来也很放方便,提高了开发效率。
状态管理,可以看做是一个仓库。 这个仓库可以是所有的组件都可以去这个仓库里面去数据。(就消除了层级的问题)
现在版本是vuex4.x,它是支持vue3的
如果是vue2的版本,使用是vuex3.x
但是4.x也不是最新的版本。 pinia是最新版(网称:大菠萝)
使用
因为我们使用脚手架创建项目的时候,已经选择vuex, 所以呢可以直接在项目中使用。
但是如果在创建项目的时候,没有选择上,就需要我们手工安装。
npm i vuex
vuex也是一个插件,所以需要在main.js 使用use()来加载插件。
1.使用方式
router/index.js //文档路径
// 1.从vuex导入了一个创建仓库的方法
import { createStore } from 'vuex'
// 2.然后使用了这个方法创建了一个仓库对象,然后导出
const store = createStore({
state: { //用来存放共享的数据的,类似全局的data
},
getters: { //提供统一取数据的方法 // 如果取都有相同的操作就可以定义在这里(就像是以全局的computed)
},
mutations: {
},
actions: {
},
modules: {
}
})
export default store
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store' // ./store/index.js
const app = createApp(App)
app.use(store) // 3.在vue实例中挂载了这个仓库.
app.use(router)
app.mount('#app')
state
用来存放共享的数据的,类似全局的data
store/index.js
const store = createStore({
state: { // 用来存放共享的数据的,类似全局的data
count: 18,
list: [2,3,3,4,5,88,22,33,11],
age: 20,
name: 'young'
},
})
几种取的方式
直接取
<div>{{ $store.state.count }}</div>
通过计算属性取
computed:{
// 当前页面要多次调用仓库的数据. 还用上面的方法的话,就重复的代码太多了,不方便维护
// 可以结合计算属性来调用. 把仓库中要取的值,当做计算属性的依赖就可以了.
// 虽然结合计算属性可以方便的一点的调用,但是还是有代码冗余,所以vuex中就提供了辅助函数给我们更方便的调用数据
// 具体的使用方法看AboutView.vue
count(){
return this.$store.state.count
},
list(){
return this.$store.state.list
},
age(){
return this.$store.state.age
},
name(){
return this.$store.state.name
}
},
通过辅助函数mapState取
<script>
// 要在这个组件中取到多个共享数据
// 可以使用mapState()来帮助我们生成计算属性
// 1. 先导入mapState方法
import { mapState } from 'vuex'
export default {
data(){
return {
count: 0
}
},
computed:{
// 2
// mapState是一个函数
// 可以接收一个数组参考
// 数组里面的每一项就是要取仓库中字段
...mapState(['count','list','age','name'])
}
}
</script>
getters
提供统一取数据的方法 // 如果取都有相同的操作就可以定义在这里(就像是以全局的computed)
store/index.js
const store = createStore({
state: { // 用来存放共享的数据的,类似全局的data
list: [2,3,3,4,5,88,22,33,11],
},
getters: { // 提供统一取数据的方法 // 如果取都有相同的操作就可以定义在这里(就像是以全局的computed)
// 把list过滤一遍里面呢只有偶数
getevenList(state){
const oulist = state.list.filter(item=>{
return item%3 == 0
})
return oulist
}
}
})
在组件中使用
直接使用
this.$store.getters.getevenList
使用辅助函数 mapGetters
<script>
// 导入 mapGetters 方法
import { mapGetters } from 'vuex'
export default {
computed:{
...mapGetters(['getevenList']),
}
}
</script>
mutations
修改数据的方法 (只能写同步代码,不能写异步)
const store = createStore({
state: { // 用来存放共享的数据的,类似全局的data
count: 18,
age: 20,
},
mutations: { // 修改数据的方法
changeCount(state){ // 提供了一个修改state.count的方法
state.count++
},
changeAge(state){
state.age++
}
},
})
直接通过$store.commit()调用
methods:{
changecount(){
// 虽然可以这么改,但是不建议这么做, (不好追踪的修改)
// 既然是仓库中的数据,就要使用仓库中的方法去修改
// this.$store.state.count = 100
// console.log(this.$store.state.count)
// 要使用$store的commit() 来触发mutations
this.$store.commit('changeCount')
},
changeage(){
this.$store.commit('changeAge')
}
},
通过mapMutations 辅助函数生成对应的方法来调用
<div>
<button @click="changeCount">修改count</button>
<button @click="changeAge">修改age</button>
</div>
<script>
import { mapGetters } from 'vuex'
// 导入 mapMutations 的方法
import { mapMutations } from 'vuex'
export default {
methods:{
...mapMutations(['changeCount','changeAge'])
// 就相当于是在方法中定义了这两个方法来触发mutations
},
}
</script>
actions 异步修改数据的方法
虽然是异步,但是也要通过mutations去修改
import myaxios from '@/utils/axios'
// 1.从vuex导入了一个创建仓库的方法
import { createStore } from 'vuex'
const store = createStore({
state: { // 用来存放共享的数据的,类似全局的data
age: 20,
mylist: [] // 定义数组保存数据
},
mutations: { // 修改数据的方法 (同步)
changeAge(state){
state.age++
},
setList(state,list){
// 定义一个mutations 来修改数组, 转进来什么就修改什么
state.mylist = list
}
},
actions: { // 异步修改数据的方法
// 虽然是异步,但是也要通过mutations去修改
asyncChangeAge(context){ // context就是相当于仓库对象 , $store
console.log(context)
// 3秒后再修改age
setTimeout(()=>{
context.commit('changeAge')
},3000)
},
asyncSetList(context){
// 需求: 要请求接口拿到数据后,再给state, 这个请求是异步, 所以就要写在actions中
myaxios.get('city').then(res=>{
// console.log(res)
if(res.status==0){
context.commit('setList', res.data.cities)
}
})
}
},
})
通过$store.dispatch() 调用
this.$store.dispatch('asyncChangeAge')
this.$store.dispatch('asyncSetList')
modules
把仓库分成一个一个小仓库(模块化)
小仓库都可以写vuex特有的4个属性: state getters mutations action
state 得是函数然后返回一个对象
store/user.js 专门用于存放用户信息的仓库
const user = { // 用来保存用户的一个小仓库
namespaced: true, // 命名空间, 调用里面的方法就要通过仓库名称
state(){
return {
name:'young',
age: 18
}
},
mutations: {
changName(state){
state.name = 'yyds'
},
changeAge(state){
state.age++
}
}
}
export default user
store/index.js 挂载这个user仓库
import { createStore } from 'vuex'
import user from './user'
const store = createStore({
modules: { // 仓库模块化
// 在这个modules中加载一个小仓库
user:user
},
})
export default store
在 组件中使用小仓库的数据
要通过小仓库的名称
{{this.$store.state.user.name}}--{{ this.$store.state.user.age}}
小仓库有命名空间,调用方法的时候也要加上小仓库的名称
this.$store.commit('user/changName')
this.$store.commit('user/changeAge')
plugins
插件: 就是一个函数
仓库初始化好了之后会调用一次,修改的时候也会调用subscribe()
import { createStore } from 'vuex'
const store = createStore({
state: {
count: 0
},
mutations:{
changeCount(state){
state.count++
},
setCount(state,num){
state.count = num
}
},
plugins: [(store)=>{
/*
1.先判断再storage中没有存的值
有 - 赋值给state.count
没有 - 把默认值存在storage中
2. 修改的时候同步更新到storage
*/
// vuex 初始化好了之后就会触发这个方法
// console.log(store.state.count)
const local = localStorage.getItem('vuex')
// console.log(local)
if(local){
const s = JSON.parse(local)
// console.log(s)
// store.state = s
store.commit('setCount',s.count)
}else{
localStorage.setItem('vuex',JSON.stringify(store.state))
}
store.subscribe((mutation, state)=>{
// 只要有修改了就会触发这个方法
// console.log(state)
localStorage.setItem('vuex',JSON.stringify(state))
})
}]
})
export default store
vuex持久化插件
vuex-persist
1.安装
npm i vuex-persist
2.使用插件
import { createStore } from 'vuex'// 1. 导入vuex-persist的插件
import VuexPersistence from 'vuex-persist'// 2. 创建vuex-persist插件的实例
const vuexLocal = new VuexPersistence({ storage: window.localStorage // 指定用那种储存方式})
const store = createStore({ state: { count: 0, name: 'young' },
mutations:{ changeCount(state){ state.count++ },
setCount(state,num){ state.count = num } }, // 3. 使用插件
plugins: [vuexLocal.plugin]})
export default store