1.安装Vue 依赖包
npm install vuex@3 --save
vue2 只能用vuex的3版本
vue3 只能用vuex的4版本
npm view vuex versions
查看vuex所有版本
2.创建 store
src
目录下 新建 store
目录 ,创建 index.js
文件
// 引入 vue
import Vue from 'vue'
// 引入 vuex
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
// 用于存储数据
const state = {}
// 用于响应组件中的动作
const actions = {}
// 用于操作数据(state)
const mutations = {}
// 创建store
const store = new Vuex.Store({
state,
mutations,
actions
})
// 导出 store
export default store;
3.引入store
main.js 中 引入 import store from './store'
配置 store
new Vue({
el: '#app',
render:h => h(App),
router,
//将创建的共享数据对象,挂载在vue实例中
//所有的组件,就可以直接从store中获取全局的数据了
store
})
Vuex 应用
state
作用:获取数据
获取state数据的第一种方式 :
this.$store.state.全局数据名称
第二种方式 :
从vuex中按需导入mapState 函数
import { mapState } from 'vuex'
通过刚才导入的mapState 函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
computed: {
//数组写法 count 是store中全局共享数据名称 获取store中的数据
...mapState(['count'])
// 对象写法
...mapState({count:'count',...})
}
mutations
作用:修改全局state中的数据(用于操作数据)
只能 通过 mutations
修改 state
中的数据,可以集中监控所有数据的变化。不可以直接操作 store
中的数据。
mutations
里面方法名称一般大写,方法第一个参数永远都是一个 state
代表全局对象,直接state.
属性就可以调用全局共享数据的属性,
const mutations = {
// value 参数
INCRE(state, value) {
state.sum += value
},
DECRE(state, value) {
state.sum -= value
}
}
触发mutation 的第一种方式
不传参数:this.$store.commit('方法名')
add 是Mutation中定义的函数名
传参数 : this.$store.commit('方法名',参数)
触发mutation 的第二种方式
从 vuex
中按需导入 mapMutations
函数
import { mapMutations } from 'vuex'
通过刚才导入的 mapMutations
函数,将需要的 mutations
,映射为当前组件的 methods
方法
methods: {
// 数组写法 吧全局mutations里面的sub、subN函数映射为当前组件的methods (如果有参数需要触发的时候传过来)
...mapMutations(['sub', 'subN']),
// 对象写法 (如果有参数需要触发的时候传过来)
...mapMutations({sub:'sub', subN:'subN'}),
}
this.sub();//可以直接调用
this.subN();//可以直接调用
注意:在 mutations
中不要执行异步操作,mutations
里面只处理简单方法,没有业务逻辑的
actions
作用:用于处理异步任务
如果通过异步操作变更数据,必须通过 action
,而不能使用 Mutation
,但是在 Action
还是要通过触发 Mutation
的方式间接变更数据
action
方法第一个参数永远都是一个 context
相当于new出来的 store
的实体对象
修改state中的数据必须通过 mutations
触发Actions 的第一种方式
this.$store.dispatch('方法名') //addAsync adction中的函数 dispatch函数 专门用来触发 action
触发Actions 的第二种方式
从vuex中按需导入 mapActions
函数
import { mapActions } from 'vuex'
通过刚才导入的 mapActions
函数,将需要的 actions
函数 ,映射为当前组件的methods方法
methods: {
// 数组方式 (方法名称必须和vuex里面的方法相同)
...mapActions(['方法名1', '方法名2'])
// 对象方式
...mapActions({ 方法名1: 'action里面的方法名1',方法名2: 'action里面的方法名2' })
}
getters
作用: 包装作用,不会修改数据(用于 state 中数据加工)
在getters中定义一个函数
//定义函数
showNum(state) {
return '当前最新数据是[' + state.count + ']'
}
使用getters第一种方式
this.$store.getters.名称
this.$store.getters.showNum
使用getters第二种方式
从vuex中按需导入 mapGetters
函数
//组件访问state中数据的第二种方式 先导入
import { mapGetters } from 'vuex';
通过刚才导入的mapGetters函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
computed: {
// 数组写法(方法名称必须和vuex里面的方法相同)
...mapGetters(['方法名']),
// 对象写法
...mapGetters({ 方法名: 'getter里面的方法名称' })
}
vuex 模块化+命名空间
目的:代码更好维护,让多种类数据更加明确
开启命名空间后,读取 state 数据
this.$store.state.countAbout.sum // 直接的读取
...mapState('countAbout', ["sum", "school", "subject"]) // 借助mapState读取
开启命名空间后,读取 getters 数据
this.$store.getters[countAbout/bigSum] // 直接的读取
...mapGetters('countAbout', ['bigSum']) //借助mapGetters读取
开启命名空间后,读取 dispatch 数据
this.$store.dispatch('countAbout/increOdd', val) // 直接的读取
...mapActions('countAbout', { handleIncreOdd: 'increOdd', handleIncreWait: 'increWait' }) // 借助 mapActions 读取
开启命名空间后,读取 commit 数据
this.$store.commit('countAbout/INCRE', val) // 直接的读取
...mapMutations('countAbout', { handleIncre: 'INCRE', handleDecre: 'DECRE' }) // 借助 mapMutations 读取
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import countOptions from "./modules/count"
import personOptions from "./modules/person"
// 创建store并导出 store
export default new Vuex.Store({
modules: {
countAbout: countOptions,
personAbout: personOptions
}
})
store/modules/count.js
Demo1 ==> 计数
Count.vue
<template>
<div>
{{sum}}
<p>getters:{{bigSum}}</p>
<p> {{school}}, {{subject}}</p>
<button @click="handleIncre(2)">+2</button>
<button @click="handleDecre(3)">-3</button>
<button @click="handleIncreOdd(1)">奇数加1</button>
<button @click="handleIncreWait(1)">1s后+1</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex"
export default {
computed: {
// sum() {
// return this.$store.state.sum
// },
// ...mapGetters(['bigSum']),//数组写法
...mapGetters({ bigSum: 'bigSum' }), // 对象写法
// ...mapState(["sum", "school", "subject"]) //数组写法
...mapState({ sum: "sum", school: "school", subject: "subject" }) // 对象写法
},
methods: {
// 写法一
// handleIncre(val) {
// this.$store.commit('INCRE', val)
// },
// handleDecre(val) {
// this.$store.commit('DECRE', val)
// },
// 写法二:简写形式,参数需要从方法名传过来value(对象)
...mapMutations({ handleIncre: 'INCRE', handleDecre: 'DECRE' }),
// 写法三:简写形式,参数需要从方法名传过来value(数组) 方法名称必须和vuex里面的方法相同
// ...mapMutations(['INCRE', 'DECRE']),
// ==============================================================================================
// 写法一
// handleIncreOdd(val) {
// this.$store.dispatch('increOdd', val)
// },
// handleIncreWait(val) {
// this.$store.dispatch('increWait', val)
// },
// 写法二:
...mapActions({ handleIncreOdd: 'increOdd', handleIncreWait: 'increWait' })
// 写法三:...mapActions(["handleIncreOdd", 'handleIncreWait']) //方法名称必须和vuex里面的方法相同
},
}
</script>
<style>
</style>
stores/index.js
// 引入 vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 用于存储数据
const state = {
sum: 0,
school: 'ans',
subject: 'web'
}
// 用于操作数据(state)
const mutations = {
INCRE(state, value) {
state.sum += value
},
DECRE(state, value) {
state.sum -= value
}
}
// 用于响应组件中的动作
const actions = {
increOdd(context, value) {
if (context.state.sum % 2) {
context.commit('INCRE', value)
}
},
increWait(context, value) {
setTimeout(() => {
context.commit('INCRE', value)
}, 1000);
}
}
// 用于 state 中数据加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建store并导出 store
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
Demo2 ==> 计算小例子
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
// new Vue({
// el: '#app',
// router,
// components: { App },
// template: '<App/>'
// })
new Vue({
el: '#app',
render:h => h(App),
router,
//将创建的共享数据对象,挂载在vue实例中
//所有的组件,就可以直接从store中获取全局的数据了
store
})
store.js
import { subset } from 'semver'
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//state中存放的就是全局共享的数据
state: {
//全局count值為0
count: 0
},
mutations: {
//定义一个add函数 第一个参数永远都是一个state 代表全局对象
//加1
add(state) {
state.count++
},
//加N
addN(state, step) {
state.count += step
},
//减1
sub(state) {
state.count--
},
//减N
subN(state, step) {
state.count -= step
}
},
actions: {
//异步操作 context相当于new 出来的store的实体对象
addAsync(context) {
setTimeout(() => {
//修改state中的数据必须通过mutations
context.commit('add')
}, 2000)
},
//等会2秒异步加N
addAsyncN(context, step) {
setTimeout(() => {
//修改state中的数据必须通过mutations
context.commit('addN', step)
}, 2000)
},
//等待2秒异步减1
subAsync(context) {
setTimeout(() => {
//修改state中的数据必须通过mutations
context.commit('sub')
}, 2000)
},
//等待2秒异步减N
subAsyncN(context, step) {
setTimeout(() => {
//修改state中的数据必须通过mutations
context.commit('subN', step)
}, 2000)
}
},
getters: {
//定义函数
showNum(state) {
return '当前最新数据是[' + state.count + ']'
}
}
})
addition.vue 加法组件
<template>
<div>
<!-- 加法组件 -->
<!-- 组件访问state中数据的第一种方式 this.$store.state.全局数据名称 -->
<h3>当前最新的count值为:{{ $store.state.count }}</h3>
<h3>getter包装的:{{ $store.getters.showNum }}</h3>
<button @click="btnadd">+1</button>
<button @click="btnadd2">+3</button>
<button @click="btnadd3">等待2秒异步+1</button>
<button @click="btnadd4">等待2秒异步+10</button>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods: {
//调用mutations中提供的一个函数
btnadd() {
this.$store.commit('add');
},
btnadd2() {
this.$store.commit('addN', 3);
},
btnadd3() {
//dispatch函数 专门用来触发 action
this.$store.dispatch('addAsync');
},
btnadd4() {
//dispatch函数 专门用来触发 action
this.$store.dispatch('addAsyncN', 10);
},
},
};
</script>
subtraction.vue 减法组件
<template>
<div>
<!-- 减法组件 -->
<h3>当前最新的count值为:{{ count }}</h3>
<h3>getter包装的:{{ showNum }}</h3>
<button @click="sub">-1</button>
<button @click="subN(3)">-3</button>
<button @click="btnSub3">等待2秒异步-1</button>
<button @click="btnSub4">等待2秒异步-10</button>
</div>
</template>
<script>
//组件访问state中数据的第二种方式 先导入
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex';
export default {
data() {
return {};
},
computed: {
//...展开运算符 吧全局里面的那些数据映射为当前组件的计算属性
//count store中全局共享数据名称 获取store中的数据
...mapState(['count']),
...mapGetters(['showNum']),
},
methods: {
...mapMutations(['sub', 'subN']), //吧全局mutations里面的sub函数映射为当前组件的methods
...mapActions(['subAsync', 'subAsyncN']),
// btnSub(){
// this.sub();//或者直接加到@click上
// },
// btnSub2(){
// this.subN(3);//或者直接加到@click上
// },
btnSub3() {
this.subAsync(); //或者直接加到@click上
},
btnSub4() {
this.subAsyncN(10); //或者直接加到@click上
},
},
};
</script>
App.vue 跟组件
<template>
<div>
<my-add></my-add>
<p>-------------------------------------------</p>
<my-sub></my-sub>
</div>
</template>
<script>
//导入组件
import addition from './components/addition.vue';
import subtraction from './components/subtraction.vue';
export default {
name: 'App',
//注册组件
components: {
'my-add': addition,
'my-sub': subtraction,
}
}
</script>
<style>
</style>
效果图如下: