①state:定义初始数据。
②mutations:更改Vuex的store中的状态的唯一方法是提交mutation
③getters:可以对state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性,但是 getters 可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用 getters。
④actions:异步操作初始数据,其实就是调用mutations里面的方法。
⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。
store文件夹index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
lists: [
// { id: 4, name: 'DS', ctime: "2020/01/01" },
// { id: 3, name: '奥迪', ctime: "2020/01/01" },
// { id: 2, name: '宝马', ctime: "2020/01/01" },
// { id: 1, name: '奔驰', ctime: "2020/01/01" },
],
brand: {}
},
mutations: {
init(state, list) {
state.lists = list
},
del(state, id) { //state 上下文的state id外界传过来的值
const index = state.lists.findIndex(item => item.id == id)
state.lists.splice(index, 1)
},
add(state, brand) {
state.lists.unshift(brand)
}
},
getters: {
getCount(state) {
return state.lists.length
}
},
actions: {
getList(context) {
console.log(context)
const list = [
{ id: 4, name: 'DS', ctime: "2020/01/01" },
{ id: 3, name: '奥迪', ctime: "2020/01/01" },
{ id: 2, name: '宝马', ctime: "2020/01/01" },
{ id: 1, name: '奔驰', ctime: "2020/01/01" },
]
setTimeout(() => {
context.commit('init', list)
}, 2000)
}
},
modules: {}
})
add.vue 文件
<template>
<div class="container">
<el-form :model="$store.state.brand" label-width="150px">
<el-form-item label="品牌名称:">
<el-input v-model="$store.state.brand.name" placeholder="请输入品牌名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "add",
methods: {
onSubmit() {
console.log(this.$store.state.brand.name)
const obj = {
id: this.$store.state.lists[0].id + 1,
name: this.$store.state.brand.name,
ctime: new Date().toLocaleDateString()
}
this.$store.commit('add', obj)
}
},
}
</script>
<style>
</style>
父组件
<template>
<div class="container">
<Add />
<hr>
<h3>品牌总数:{{getCount}}</h3>
<template>
<el-table :data="lists" style="width: 100%" border>
<el-table-column prop="id" label="品牌id" align="center" header-align="center">
</el-table-column>
<el-table-column prop="name" label="品牌名称" align="center" header-align="center">
</el-table-column>
<el-table-column prop="ctime" label="添加时间" align="center" header-align="center">
</el-table-column>
<el-table-column label="操作" align="center" header-align="center">
<template slot-scope="scope">
<el-button type="success" @click="handleEdit(scope.row.id)">编辑</el-button>
<el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
</div>
</template>
<script>
import Add from "./Add"
// mapState():将vuex中的状态数据映射到组件内部
import { mapState } from "vuex" //放到computed解构
import { mapGetters } from "vuex" //放到computed解构
import { mapMutations } from 'vuex' //放到methods 解构
import { mapActions } from 'vuex' //放到methods 解构
export default {
name: "helle",
components: {
Add
},
created() {
// this.$store.dispatch('getList')
this.getList()
console.log(mapState(["lists", "brand"]))
},
computed: {
...mapState(["lists", "brand"]),
...mapGetters(['getCount'])
},
methods: {
...mapMutations(['del']),
...mapActions(['getList']),
handleEdit(id) {
console.log(id)
},
handleDelete(id) {
console.log(id)
//通过this.$store.commit方法触发mutations种定义的del方法 第二个为传递的参数
// this.$store.commit('del', id)
this.del(id)
}
},
}
</script>
<style>
</style>
Vuex是什么?
Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
使用 Vuex 统一管理状态的好处
① 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
② 能够高效地实现组件之间的数据共享,提高开发效率
③ 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步
一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中;对于组件中的私有数据,依旧存储在组件自身的 data 中即可
Vuex 的基本使用
npm install vuex --save 安装 vuex 依赖包
import Vuex from 'vuex'
Vue.use(Vuex) 导入 vuex 包
const store = new Vuex.Store({
// state 中存放的就是全局共享的数据
state: { count: 0 }
})
new Vue({
el: '#app',
render: h => h(app),
router,
// 将创建的共享数据对象,挂载到 Vue 实例中
// 所有的组件,就可以直接从 store 中获取全局的数据了
store
})
Vuex 中的主要核心
State
State
提供唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储。
// 创建store数据源,提供唯一公共数据
const store = new Vuex.Store({
state: { count: 0 }
})
组件访问 State 中数据的第一种方式:
this.$store.state
.全局数据名称
组件访问 State 中数据的第二种方式:
// 1\. 从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex'
通过刚才导入的 mapState 函数,将当前组件需要的全局数据,映射为当前组件的 computed 计算属性:
// 2\. 将全局数据,映射为当前组件的计算属性
computed: {
...mapState(['count'])
}
Mutation
Mutation
用于变更 Store中 的数据。
只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。
通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
// 定义 Mutation
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state) {
// 变更状态
state.count++
}
}
})
// 触发mutation
methods: {
handle1() {
// 触发 mutations 的第一种方式
this.$store.commit('add')
}
}
可以在触发 mutations 时传递参数:
// 定义Mutation
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
addN(state, step) {
// 变更状态
state.count += step
}
}
})
// 触发mutation
methods: {
handle2() {
// 在调用 commit 函数,
// 触发 mutations 时携带参数
this.$store.commit('addN', 3)
}
}
this.$store.commit()
是触发 mutations 的第一种方式
触发 mutations 的第二种方式:
// 1\. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'
通过刚才导入的 mapMutations 函数,将需要的 mutations 函数,映射为当前组件的 methods 方法:
// 2\. 将指定的 mutations 函数,映射为当前组件的 methods 函数
methods: {
...mapMutations(['add', 'addN'])
}
Action
Action
用于处理异步任务。
如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action 中还是要通过触发
Mutation 的方式间接变更数据
// 定义 Action
const store = new Vuex.Store({
// ...省略其他代码
mutations: {
add(state) {
state.count++
}
},
actions: {
addAsync(context) {
setTimeout(() => {
context.commit('add')
}, 1000)
}
}
})
// 触发 Action
methods: {
handle() {
// 触发 actions 的第一种方式
this.$store.dispatch('addAsync')
}
}
触发 actions 异步任务时携带参数:
// 定义 Action
const store = new Vuex.Store({
// ...省略其他代码
mutations: {
addN(state, step) {
state.count += step
}
},
actions: {
addNAsync(context, step) {
setTimeout(() => {
context.commit('addN', step)
}, 1000)
}
}
})
// 触发 Action
methods: {
handle() {
// 在调用 dispatch 函数,
// 触发 actions 时携带参数
this.$store.dispatch('addNAsync', 5)
}
}
this.$store.dispatch()
是触发 actions 的第一种方式
触发 actions 的第二种方式:
// 1\. 从 vuex 中按需导入 mapActions 函数
import { mapActions } from 'vuex'
通过刚才导入的 mapActions 函数,将需要的 actions 函数,映射为当前组件的 methods 方法:
// 2\. 将指定的 actions 函数,映射为当前组件的 methods 函数
methods: {
...mapActions(['addASync', 'addNASync'])
}
Getter
Getter
用于对 Store 中的数据进行加工处理形成新的数据。
Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。
Store 中数据发生变化,Getter 的数据也会跟着变化。
// 定义 Getter
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
showNum: state => {
return '当前最新的数量是【' + state.count + '】'
}
}
})
使用 getters 的第一种方式:this.$store.getters.名称
使用 getters 的第二种方式:
import { mapGetters } from 'vuex'
computed: {
...mapGetters(['showNum'])
}
2.2 Mutations
mutations
是操作state
数据的方法的集合,比如对该数据的修改、增加、删除等等。
2.2.1 Mutations使用方法
mutations
方法都有默认的形参:
([state] [,payload])
- state是当前VueX对象中的state
- payload是该方法在被调用时传递参数使用的
例如,我们编写一个方法,当被执行时,能把下例中的name值修改为"jack",我们只需要这样做:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.store({
state:{
name:'helloVueX'
},
mutations:{
//es6语法,等同edit:funcion(){...}
edit(state){
state.name = 'jack'
}
}
而在组件中,我们需要这样去调用这个mutation——例如在App.vue的某个method中:
this.$store.commit('edit')
2.2.2 Mutation传值
在实际生产过程中,会遇到需要在提交某个mutation
时需要携带一些参数给方法使用。
单个值提交时:
this.$store.commit('edit',15)
当需要多参提交时,推荐把他们放在一个对象中来提交:
this.$store.commit('edit',{age:15,sex:'男'})
接收挂载的参数:
edit(state,payload){
state.name = 'jack'
console.log(payload) // 15或{age:15,sex:'男'}
}
另一种提交方式
this.$store.commit({
type:'edit',
payload:{
age:15,
sex:'男'
}
})
2.2.3 增删state中的成员
为了配合Vue的响应式数据,我们在
Mutations
的方法中,应当使用Vue提供的方法来进行操作。如果使用delete
或者xx.xx = xx
的形式去删或增,则Vue不能对数据进行实时响应。
-
Vue.set:为某个对象设置成员的值,若不存在则新增。如对state对象中添加一个age成员:
Vue.set(state,"age",15)
-
Vue.delete:删除成员。如将刚刚添加的age成员删除:
Vue.delete(state,'age')
2.3 Getters 对state中的成员进行筛选过滤
getters中的方法有两个默认参数:
([state] , [getters])
state:当前VueX对象中的状态对象
getters:当前getters对象,用于将getters下的其他getter拿来用
-
在getters中自定义方法
getters:{
nameInfo(state){
return "姓名:"+state.name
},
fullInfo(state,getters){
return getters.nameInfo+'年龄:'+state.age
}
}
-
在组件中调用该方法
this.$store.getters.fullInfo
2.4 Actions—异步操作
mutations
只能处理同步函数,直接在mutation
方法中进行异步操作,将会引起数据失效。所以提供了Actions
来专门进行异步操作,最终提交mutation
方法。actions
和mutations
的区别:
Actions
提交的是mutations
,而不是直接变更状态。也就是说,actions
会通过mutations
,让mutations
帮他提交数据的变更。
Action
可以包含任意异步操作。ajax
、setTimeout
、setInterval
不在话下。
Actions中的方法有两个默认参数:([
context
] , [payload
])
context
:上下文(相当于箭头函数中的this)对象
payload
:挂载参数
-
在actions中自定义异步方法:如在两秒中后执行edit方法(由于setTimeout是异步操作,所以需要使用actions)。
actions:{
edit(context,payload){
setTimeout(()=>{
context.commit('edit',payload)
},2000)
}
}
-
在组件中调用该异步方法
this.$store.dispatch('edit',{age:15})
拓展:由于是异步操作,所以我们可以对异步操作封装为一个Promise对象,上面的异步方法可优化为:
actions:{
edit(context,payload){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
context.commit('edit',payload)
resolve()
},2000)
})
}
}
2.5 Modules
当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将
store
分割成模块(module
)。每个模块拥有自己的state
、mutation
、action
、getter
、甚至是嵌套子模块——从上至下进行同样方式的分割。
Modules :{
a:{
state:{},
getters:{},
....
}
}
组件内调用模块a的状态:
this.$store.state.a
而提交或者dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法:
this.$store.commit('editKey')
this.$store.dispatch('aEditKey')
2.5.1 模块的细节
模块中 mutations
和getters
中的方法接受的第一个参数是自身局部模块内部的state
Modules :{
a:{
state:{key:5},
mutations:{
editKey(state){
state.key = 9
}
},
....
}
}
-
getters
中方法的第三个参数是根节点状态
Modules :{
a:{
state:{key:5},
getters:{
getKeyCount(state,getter,rootState){
return rootState.key + state.key
}
},
....
}
}
actions
中方法获取局部模块状态是context.state
,根节点状态是context.rootState
Modules :{
a:{
state:{key:5},
actions:{
aEidtKey(context){
if(context.state.key === context.rootState.key){
context.commit('editKey')
}
}
},
....
}
}
三、规范目录结构
如果把整个store
都放在index.js
中是不合理的,所以需要拆分。比较合适的目录格式如下:
store:.
│ actions.js
│ getters.js
│ index.js
│ mutations.js
│ mutations_type.js ##该项为存放mutaions方法常量的文件,按需要可加入
│
└─modules
Astore.js
对应的内容存放在对应的文件中,和以前一样,在index.js
中存放并导出store
。state
中的数据尽量放在index.js
中。而modules
中的Astore
局部模块状态如果多的话也可以进行细分。
// 假设你有如下的store模块
const moduleA = {
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
};
// 在store中注册模块
const store = new Vuex.Store({
modules: {
a: moduleA
}
});
// 在组件中使用mapState获取模块状态
import { mapState } from 'vuex';
export default {
computed: {
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
count: state => state.a.count // 这里的'a'是模块名,'count'是状态名
})
},
methods: {
increment() {
this.$store.commit('a/increment'); // 使用模块名调用模块的mutation
}
}
};