状态(数据)
管理的一个 Vue 插件,对 vue 应用中多个组件的共享
状态进行集中式的管理(读/写),也是一种组件间通信的方式
,且适用于任意组件间通信
。简单来说就是
多个组件需要共享数据时
npm i vuex
注:
如果执行npm i vuex
默认安装的是vuex4版本,而vuex4版本只能在vue3里面使用,所以如果你用的是vue2需要指定安装vuex3的版本。
vue2里正确安装:
npm i vuex@3
src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
main.js
中创建vm时传入store
配置项......
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入store
import store from './store/index.js'
......
//创建vm
new Vue({
el:'#app',
render: h => h(App),
store
})
actions
、配置mutations
,操作文件store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引用Vuex
Vue.use(Vuex)
const actions = {
//响应组件中加的动作
jia(context,value){
// console.log('actions中的jia被调用了',miniStore,value)
context.commit('JIA',value)
},
}
const mutations = {
//执行加
JIA(state,value){
// console.log('mutations中的JIA被调用了',state,value)
state.sum += value
}
}
//初始化数据
const state = {
sum:0
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
组件中读取vuex中的数据:$store.state.sum
组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)
或 $store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写
dispatch
,直接编写commit
实现效果:
结构目录:
代码示例:
main 文件
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
App组件
<template>
<Count/>
template>
<script>
import Count from './components/Count'
export default {
name:'App',
components:{Count}
}
script>
<style>
style>
Count组件
<template>
<div>
<h1>当前求和为:{{ sum }}h1>
<select v-model.number="n">
<option value="1">1option>
<option value="2">2option>
<option value="3">3option>
select>
<button @click="add">+button>
<button @click="subtract">-button>
<button @click="addOdd">当前和为奇数再加button>
<button @click="addWait">等一等再加button>
div>
template>
<script>
export default {
name: "Count",
data() {
return {
n: 1, //选择数
sum: 0, //求和数
};
},
methods: {
add() {
this.sum += this.n;
},
subtract() {
this.sum -= this.n;
},
addOdd() {
if (this.sum % 2) {
this.sum += this.n;
}
},
addWait() {
setTimeout(() => {
this.sum += this.n;
}, 500);
},
},
};
script>
<style>
h1 {
color: pink;
}
select {
width: 50px;
background: pink;
}
button {
margin: 5px;
padding: 5px 10px;
background: pink;
border: none;
cursor: pointer;
}
style>
实现效果:
结构目录:
main文件
import Vue from 'vue'
import App from './App.vue'
//引入store里面的index.js文件,vue里默认引入的就是index文件
import store from './store'
Vue.config.productionTip = false
const vm = new Vue({
render: h => h(App),
store //安装store
}).$mount('#app')
console.log(vm);
App组件
<template>
<Count/>
template>
<script>
import Count from './components/Count'
export default {
name:'App',
components:{Count}
}
script>
<style>
style>
Count组件
<template>
<div>
<h1>当前求和为:{{ $store.state.sum }}h1>
<select v-model.number="n">
<option value="1">1option>
<option value="2">2option>
<option value="3">3option>
select>
<button @click="add">+button>
<button @click="subtract">-button>
<button @click="addOdd">当前和为奇数再加button>
<button @click="addWait">等一等再加button>
div>
template>
<script>
export default {
name: "Count",
data() {
return {
n: 1, //选择数
};
},
methods: {
add() {
this.$store.commit("ADD", this.n);
},
subtract() {
this.$store.commit("SUBTRACT", this.n);
},
addOdd() {
this.$store.dispatch("addOdd", this.n);
},
addWait() {
this.$store.dispatch("addWait", this.n);
},
},
};
script>
<style>
h1 {
color: pink;
}
select {
width: 50px;
background: pink;
}
button {
margin: 5px;
padding: 5px 10px;
background: pink;
border: none;
cursor: pointer;
}
style>
store里面的index.js 文件
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
};
},
addWait(context, value) {
setTimeout(() => {
context.commit('ADD', value)
}, 500);
}
}
//准备mutations对象——修改state中的数据
const mutations = {
ADD(context, value) {
context.sum += value
},
SUBTRACT(context, value) {
context.sum -= value
},
}
//准备state对象——保存具体的数据
const state = {
sum: 0, //求和数
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
在store.js
中追加getters
配置
......
const getters = {
bigSum(state){
return state.sum * 10
//靠返回值
}
}
//创建并暴露store
export default new Vuex.Store({
......
getters
})
组件中读取数据:$store.getters.bigSum
state
中的数据为计算属性computed: {
//借助mapState生成计算属性:sum、school、subject(对象写法)
...mapState({sum:'sum',school:'school',subject:'subject'}),
//借助mapState生成计算属性:sum、school、subject(数组写法)
...mapState(['sum','school','subject']),
},
getters
中的数据为计算属性computed: {
//借助mapGetters生成计算属性:bigSum(对象写法)
...mapGetters({bigSum:'bigSum'}),
//借助mapGetters生成计算属性:bigSum(数组写法)
...mapGetters(['bigSum'])
},
actions
对话的方法,即:包含$store.dispatch(xxx)
的函数methods:{
//靠mapActions生成:incrementOdd、incrementWait(对象形式)
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
//靠mapActions生成:incrementOdd、incrementWait(数组形式)
...mapActions(['jiaOdd','jiaWait'])
}
mutations
对话的方法,即:包含$store.commit(xxx)
的函数methods:{
//靠mapActions生成:increment、decrement(对象形式)
...mapMutations({increment:'JIA',decrement:'JIAN'}),
//靠mapMutations生成:JIA、JIAN(对象形式)
...mapMutations(['JIA','JIAN']),
}
备注:在四个方法使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
index.js
和Count组件
index.js文件
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
/* add(context, value) {
context.commit('ADD', value)
},
subtract(context, value) {
context.commit('SUBTRACT', value)
}, */
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
};
},
addWait(context, value) {
setTimeout(() => {
context.commit('ADD', value)
}, 500);
}
}
//准备mutations对象——修改state中的数据
const mutations = {
ADD(context, value) {
context.sum += value
},
SUBTRACT(context, value) {
context.sum -= value
},
}
//准备state对象——保存具体的数据
const state = {
sum: 0, //求和数
school:'哔站',
subject:'前端'
}
// 对state对象里的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
Count组件
<template>
<div>
<h1>当前求和为:{{ sum }}h1>
<h3>放大十倍后的和为:{{ bigSum }}h3>
<h3>我在{{ school }}学{{ subject }}h3>
<select v-model.number="n">
<option value="1">1option>
<option value="2">2option>
<option value="3">3option>
select>
<button @click="add(n)">+button>
<button @click="subtract(n)">-button>
<button @click="addOdd(n)">当前和为奇数再加button>
<button @click="addWait(n)">等一等再加button>
div>
template>
<script>
// 导入4个map方法
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
name: "Count",
data() {
return {
n: 1, //选择数
};
},
computed: {
//靠程序员自己亲自去写计算属性
/* sum(){
return this.$store.state.sum
},
school(){
return this.$store.state.school
},
subject(){
return this.$store.state.subject
}, */
//借助mapState生成计算属性,从state中读取数据。(对象写法)
// ...mapState({ sum: "sum", school: "school", subject: "subject" }),
//借助mapState生成计算属性,从state中读取数据。(数组写法)
// 数组写法必须数据名和计算方法名一致
...mapState(["sum", "school", "subject"]),
// ...............................
//靠程序员自己亲自去写计算属性
/* bigSum(){
return this.$store.getters.bigSum
}, */
//借助mapGetters生成计算属性,从getters中读取数据。(对象写法)
// ...mapGetters({bigSum:'bigSum'})
//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters(["bigSum"]),
},
methods: {
//程序员亲自写方法
/* add() {
this.$store.commit("ADD", this.n);
},
subtract() {
this.$store.commit("SUBTRACT", this.n);
},
addOdd() {
this.$store.dispatch("addOdd", this.n);
},
addWait() {
this.$store.dispatch("addWait", this.n);
}, */
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({ add: "ADD", subtract: "SUBTRACT" }), //必须在插值语法中传入实参,不然默认是event事件对象
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(数组写法)数组写法必须数据名和方法名一致,这里改了,上面调用的时候也要改。
// ...mapMutations({ADD:'ADD',SUBTRACT:'SUBTRACT'})
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
// ...mapActions({addOdd:'addOdd',addWait:'addWait'})
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
...mapActions(["addOdd", "addWait"]),
},
};
script>
<style>
h1,
h3 {
color: pink;
}
select {
width: 50px;
background: pink;
}
button {
margin: 5px;
padding: 5px 10px;
background: pink;
border: none;
cursor: pointer;
}
style>
目的:让代码更好维护,让多种数据分类更加明确。
修改store.js
const countAbout = {
namespaced:true,//开启命名空间
state:{x:1},
mutations: { ... },
actions: { ... },
getters: {
bigSum(state){
return state.sum * 10
}
}
}
const personAbout = {
namespaced:true,//开启命名空间
state:{ ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})
开启命名空间后,组件中读取state数据:
//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),
开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])
开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
main文件
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
App组件
<template>
<div>
<Count />
<Person />
div>
template>
<script>
import Count from "./components/Count";
import Person from "./components/Person";
export default {
name: "App",
components: { Count, Person },
};
script>
<style>
style>
Count组件
使用4种map方法
<template>
<div>
<h1>当前求和为:{{ sum }}h1>
<h3>放大十倍后的和为:{{ bigSum }}h3>
<h3>我在{{ school }}学{{ subject }}h3>
<h3 style="color: red">Person组件的总人数是:{{ persons.length }}h3>
<select v-model.number="n">
<option value="1">1option>
<option value="2">2option>
<option value="3">3option>
select>
<button @click="add(n)">+button>
<button @click="subtract(n)">-button>
<button @click="addOdd(n)">当前和为奇数再加button>
<button @click="addWait(n)">等一等再加button>
div>
template>
<script>
// 导入4个map方法
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
name: "Count",
data() {
return {
n: 1,
};
},
computed: {
//借助mapState生成计算属性,从state中读取数据。(数组写法)
...mapState('CountOptions',["sum", "school", "subject"]),
...mapState('PersonOptions',["persons"]),
//借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters('CountOptions',["bigSum"]),
},
methods: {
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations('CountOptions',{ add: "ADD", subtract: "SUBTRACT" }),
//借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
...mapActions('CountOptions',["addOdd", "addWait"]),
},
};
script>
<style>
h1,
h3,
li {
color: pink;
}
select {
width: 50px;
background: pink;
}
button {
margin: 5px;
padding: 5px 10px;
background: pink;
border: none;
cursor: pointer;
}
style>
Person组件
不使用map方法,和上面的写法进行一个对比
<template>
<div>
<h1>人员列表h1>
<h3 style="color: red">Count组件求和为:{{ sum }}h3>
<h3>列表中第一个人的名字是:{{ firstPersonName }}h3>
<input type="text" placeholder="请输入名字" v-model="name" />
<button @click="add">添加button>
<button @click="addZhang">添加一个姓张的人button>
<button @click="addPersonServer">随机添加一条语录button>
<ul>
<li v-for="p in persons" :key="p.id">{{ p.name }}li>
ul>
div>
template>
<script>
import { nanoid } from "nanoid";
export default {
name: "Person",
data() {
return {
name: "",
};
},
computed: {
persons() {
// return this.$store.state.persons
return this.$store.state.PersonOptions.persons;
},
sum() {
return this.$store.state.CountOptions.sum;
},
firstPersonName() {
return this.$store.getters["PersonOptions/firstPersonName"];
},
},
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit("PersonOptions/PersonAdd", personObj);
},
addZhang() {
const personObj = { id: nanoid(), name: this.name };
this.$store.dispatch("PersonOptions/addZhang", personObj);
},
addPersonServer() {
this.$store.dispatch('PersonOptions/addPersonServer')
}
},
mounted() {
console.log(this.$store);
},
};
script>
<style>
input::placeholder {
color: pink;
}
input {
border: 1px solid pink;
padding: 5px;
}
style>
store/index.js文件
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
import axios from 'axios'
import { nanoid } from 'nanoid'
//应用Vuex插件
Vue.use(Vuex)
const CountOptions = {
namespaced: true,
actions: {
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
};
},
addWait(context, value) {
setTimeout(() => {
context.commit('ADD', value)
}, 500);
}
},
mutations: {
ADD(state, value) {
state.sum += value
},
SUBTRACT(state, value) {
state.sum -= value
},
},
state: {
sum: 0, //求和数
school: '哔站',
subject: '前端',
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
const PersonOptions = {
namespaced: true,
actions: {
addZhang(context, value) {
if (value.name.indexOf('张') === 0) {
context.commit('PersonAdd', value)
} else { alert('请输入姓张的人') }
},
addPersonServer(context) {
axios({
methods: 'get',
url: 'https://api.uixsj.cn/hitokoto/get?type=social'
}).then(response => {
context.commit('PersonAdd', { id: nanoid(), name: response.data })
}, error => {
alert(error.message)
})
}
},
mutations: {
PersonAdd(state, value) {
state.persons.unshift(value)
}
},
state: {
persons: [{ id: "001", name: '张三' }]
},
getters: {
firstPersonName(state) {
return state.persons[0].name
}
}
}
//创建并暴露store
export default new Vuex.Store({
modules: {
CountOptions,
PersonOptions
}
})
对store/index.js文件
进行拆分
index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
import CountOptions from './CountOptions'
import PersonOptions from './PersonOptions'
//应用Vuex插件
Vue.use(Vuex)
//创建并暴露store
export default new Vuex.Store({
modules: {
CountOptions,
PersonOptions
}
})
CountOptions.js
export default {
namespaced: true,
actions: {
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
};
},
addWait(context, value) {
setTimeout(() => {
context.commit('ADD', value)
}, 500);
}
},
mutations: {
ADD(state, value) {
state.sum += value
},
SUBTRACT(state, value) {
state.sum -= value
},
},
state: {
sum: 0, //求和数
school: '哔站',
subject: '前端',
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
PersonOptions.js
import axios from 'axios'
import { nanoid } from 'nanoid'
export default {
namespaced: true,
actions: {
addZhang(context, value) {
if (value.name.indexOf('张') === 0) {
context.commit('PersonAdd', value)
} else { alert('请输入姓张的人') }
},
addPersonServer(context) {
axios({
methods: 'get',
url: 'https://api.uixsj.cn/hitokoto/get?type=social'
}).then(response => {
context.commit('PersonAdd', { id: nanoid(), name: response.data })
}, error => {
alert(error.message)
})
}
},
mutations: {
PersonAdd(state, value) {
state.persons.unshift(value)
}
},
state: {
persons: [{ id: "001", name: '张三' }]
},
getters: {
firstPersonName(state) {
return state.persons[0].name
}
}
}