什么是Vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信。
要点:
- vue官方搭配,专属使用 (类似于:vue-router),有专门的调试工具
- 集中式管理数据状态方案 (操作更简洁)
data() { return { 数据, 状态 }} - 数据变化是可预测的 (响应式)
vue官方提供的独立于组件体系之外的,管理公共数据的工具
Vuex中有5个内容需要学习:
- state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})
- mutations : 使用它来修改数据(类似于methods)
- getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
- actions: 发起异步请求
- modules: 模块拆分
- 其中最为重要的内容是state和mutations,需要重点掌握
Vuex的使用步骤:
- 下载Vuex
npm i vuex 或者 yarn add vuex
2. 在src目录下新建一个统一的文件夹store,并在store中创建index.js
3. 在store/index.js 中放置具体的代码,具体如下:
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
getters: {},
actions: {},
modules: {}
})
注意: 别忘了向Vue实例中注入store
在src/main.js中:
- 导入store
- 并注入Vue实例
import store from './store'
new Vue({
render: h => h(App),
store
}).$mount('#app')
1. state
vuex用它来保存公共数据
格式:
new Vuex.store({
state: {
属性名: 属性值
}
})
使用公共数据格式:
在组件中,通过this.$store.state.属性名来访问。
在模板中,则可以省略this而直接写成: {{$store.state.属性名}}
示例:
export default new Vuex.Store({
state: {
num: 8
}
)}
接下来在模板中获取并使用这个公共数据
<template>
<div>
{{ $store.state.num }} // 页面中会打印出 8
</div>
</template>
2.mutations
mutations主要用于修改state中的公共数据
定义格式:
nwe Vue.State({
mutations: {
// 每一项都是一个函数,可以声明两个形参
mutation名1:function(state ,[载荷]) {
},
mutation名2:function(state ,[载荷]) {
}
}
})
每一项都是一个函数,可以声明两个形参:
- 第一个参数是必须的,表示当前的state。在使用时不需要传入
- 第二个参数是可选的,表示载荷,是可选的。在使用时要传入的数据
使用格式:
this.$store.commit('mutation名', 实参,给第二个参数)
这里的commit是固定的方法。
示例:
export default new Vuex.Store({
state: {
num: 8
},
mutations: {
dobuleNum: function(state) {
state.num *= 2
},
}
})
接下来在App.vue中定义一个button按钮,点击来让num翻倍,
注意: 在模板中,不用加'this' ----- $store.commit(‘mutations名’)
在组件中,需要加this调用
<template>
<div>
{{ $store.state.num }}
<!-- 使用全局mutations -->
<button @click="$store.commit('dobuleNum')">全局mutations修改数据</button>
</div>
</template>
3.getters
getters的作用是在state中的数据的基础上,进一步对数据进行加工得到新数据。(与组件中computed(计算属性)一样)
定义格式:
new Vuex.store({
// 省略其他...
getters: {
// state 就是上边定义的公共数据state
getter的名字1: function(state) {
return 要返回的值
}
}
})
使用格式:
在模板中通过:$store.getters.getter的名字 来访问
示例:
export default new Vuex.Store({
state: {
num: 8
},
getters: {
tenfold(state) {
return state.num * 10
}
}
})
然后再App.vue中直接使用就行了
<template>
<div>
<p>使用全局getters:{{ $store.getters.tenfold }}</p>
</div>
</template>
4.actions
我们可以使用Action来修改state,这一点是类似于 mutation的,不同在于:
- action中可以通过调用 mutation来修改state,而不是直接变更状态。
- action 可以包含任意异步(例如ajax请求)操作。
定义格式:
new Vuex.store({
// 省略其他...
actions: {
// context对象会自动传入,它与store实例具有相同的方法和属性
action的名字: function(context, 载荷) {
// 1. 发异步请求, 请求数据
// 2. commit调用mutation来修改/保存数据
// context.commit('mutation名', 载荷)
}
}
})
使用格式:
在组件中通过`this.$store.dispatch('actions的名字', 参数)`来调用action
在模块中通过`$store.dispatch('actions的名字', 参数)`来调用action
示例:
export default {
state: {
books: []
},
mutations: {
setBooks(state, newBooks) {
state.books = newBooks;
}
},
actions: {
getBooks(context) {
axios({
method: "get",
url:
"https://www.fastmock.site/mock/37d3b9f13a48d528a9339fbed1b81bd5/book/api/books"
}).then(res => {
console.log(res);
context.commit("setBooks", res.data.data);
})
}
}
}
注意: 在state中我定义了一个数组 book:[ ]用来接收获取到的数据 , 接收到数据res后, 想赋值给book数组, 但是要记住不能直接进行赋值,必须要在mutations中定义一个赋值的函数, 在actions获取到数据.调用mutations中的函数,进行赋值.
接下来在App.vue中创建一个button按钮,点击按钮触发actions,发起axios请求获取数据,并赋值给book数组
<template>
<div>
// 触发actions 并发起axios请求数据
<button @click="$store.dispatch('getBooks')">
点击获取图书信息
</button>
</div>
</template>
5.modules
modules用来拆分index.js中的代码, 减少index.js中代码的繁多和体积,让index.js中更简洁,把相同的需要的数据和方法都提取到同一个js中
modules默认namespaced: 为false ,设置true后.,在组件中使用拆分到modules的数据和方法要加"模块名"
首先:在store文件夹下建立modules文件夹,然后再modules文件夹下自定义一个getBooks.js文件,然后将index.js中的 state、mutations、getters、actions中的相关代码剪切到getBooks.js文件中
import axios from "axios";
export default {
namespaced: true,
state: {
skills: ["vue", "html", "js"],
nubs: 20,
books: []
},
mutations: {
setBooks(state, newBooks) {
state.books = newBooks;
},
change(state, newSkills) {
state.skills = newSkills;
}
},
getters: {
sum(state) {
return state.nubs + 10;
}
},
actions: {
getBooks(context) {
axios({
method: "get",
url:
"https://www.fastmock.site/mock/37d3b9f13a48d528a9339fbed1b81bd5/book/api/books"
}).then(res => {
console.log(res);
context.commit("setBooks", res.data.data);
});
}
}
}
抽离到getBooks.js中后,在index.js中引入,并添加到modules对象中
import Vue from 'vue'
import vuex from 'vuex'
import getBooks from './modules/getBooks.js'
Vue.use(vuex)
export default new vuex.Store({
modules: {
getBooks
}
})
注意: 抽离后.组件中调用的方式就变了, 还记得我们加了namespaced: true这句话, 加了之后,引用数据和方法时都必须要加上模块名了
使用格式:
访问模块中的数据,要加上模块名
获取数据项: {{store.state.模块名.数据项名}}\ 获取getters: {{store.getters['模块名/getters名']}}
访问模块中的mutations/actions:
- 如果namespaced为true,则需要额外去补充模块名
- 如果namespaced为false,则不需要额外补充模块名
store.commit('模块名/mutations名') // namespaced为true
代码更加直观,举几个例子:
// 例子:
1. 原先写法: <p>{{$store.getters.sum}} </p> // 30
2. 抽离后的写法: <p>{{$store.gerters['getBooks/sum']}} </p> // 30
// 这里我都列举一下其他三种的方式
// state:
<p>{{ $store.state.getBooks.skills[0] }}</p>
// mutations:
<button @click="$store.commit('getBooks/change',['css','小程序','react'])"></button>
// actions:
<button @click="$store.dispatch('getBooks/getBooks')"></button>
补充: 如果要修改state/mutations/getters/actions名字,例如:可以这样写 $store.commit(‘模块名,{新名字,旧名字}’) ,其他的格式都类似如此
在使用modules时,建议都给加上namespaced!
Vuex的辅助函数map系列用法汇总
mapState/mapMutations/mapGetters/mapActions
用来优化访问的方式, 普通的写法太麻烦了,利用vuex内置的方法,可以简洁的引用vuex中的数据和方法
1. mapState函数
将state中的变量映射到当前组件中使用
使用步骤,代码如下:
// index.js中
export default new vuex.Store({
state: {
num: 10
}
})
// App.vue中
<template>
<div>
{{ num }} // 10
</div>
</template>
<script>
// 导入辅助函数mapState,它是在vuex中定义的一个工具函数。
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['num'])
// 如果需要改名字的话
...mapState({ '新名字': '旧名字' })
}
}
</script>
computed:{ …mapState() } 这里的…是对象的展开运算符,整体来看是对象的合并
2. mapMutations
// 在state中定义一个变量为a:10
// App.vue组件中
<template>
<div>
{{a}}
<button @click="add">点击+1</button>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
export default {
computed: {
...mapState(['a'])
},
methods: {
...mapMutations(['add'])
},
}
</script>
// index.js中
export default new vuex.Store({
state: {
a: 10,
},
mutations: {
add: function (state) {
state.a += 1
}
},
})
以上列举了mapState和mapMutations的语法,其他两个(mapGetters和mapActions)用法和前两个都是一样的,自行体会吧
接下来讲一下在全局中和modules情况下使用map系列的用法:
先上图:
如何使用全局state
- 直接使用: this.$store.state.xxx;
- map辅助函数:
computed: {
...mapState(['xxx']),
...mapState({'新名字': 'xxx'})
}
如何使用modules中的state
- 直接使用: this.$store.state.模块名.xxx;
- map辅助函数:
computed: {
...mapState('模块名', ['xxx']),
...mapState('模块名', {'新名字': 'xxx'})
}
如何使用全局getters
- 直接使用:
this.$store.getters.xxx - map辅助函数:
computed: {
...mapGetters(['xxx']),
...mapGetters({'新名字': 'xxx'})
}
如何使用modules中的getters
- 直接使用:
this.$store.getters.模块名.xxx - map辅助函数:
computed: {
...mapGetters('模块名', ['xxx']),
...mapGetters('模块名',{'新名字': 'xxx'})
}
如何使用全局mutations
- 直接使用:
this.$store.commit('mutation名', 参数) - map辅助函数:
methods: {
...mapMutations(['mutation名']),
...mapMutations({'新名字': 'mutation名'})
}
如何使用modules中的mutations(namespaced:true)
- 直接使用:
this.$store.commit('模块名/mutation名', 参数) - map辅助函数:
methods: {
...mapMutations('模块名', ['xxx']),
...mapMutations('模块名',{'新名字': 'xxx'})
}
如何使用全局actions
- 直接使用:
this.$store.dispatch('action名', 参数) - map辅助函数:
methods: {
...mapActions(['actions名']),
...mapActions({'新名字': 'actions名'})
}
如何使用modules中的actions(namespaced:true)
- 直接使用:
this.$store.dispatch('模块名/action名', 参数) - map辅助函数:
methods: {
...mapActions('模块名', ['xxx']),
...mapActions('模块名',{'新名字': 'xxx'})
}
今天就写到这里,谢谢各位观众老爷的观看,如果觉得写的还可以,记得一键三连哦,这篇博客前面还发过vuex核心API的关系图,和此文一起食用效果更佳哦
每日一汤:
业精于勤,荒于嬉;行成于思,毁于随。——韩愈