上篇介绍单一使用vue.js,通过props实现传值https://blog.csdn.net/maidu_xbd/article/details/89134193
本篇主要介绍使用vuex,通过store实现传值以及数据状态更改。可以理解为在store中定义全局数据,全局方法。可以供其子组件调用。
vuex安装:【npm install vuex --save】
vuex主要应用于vue.js中管理数据状态的一个库,通过创建一个集中的数据存储,供程序中所有组件访问。
Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,可理解为“单一的数据源”。
状态管理有5个核心:state、getter、mutation、action、module
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
// strict: true,
// state: {},
// getters: {},
// mutations: {},
// actions: {},
modules: {
a: moduleA,
b: moduleB
}
});
const moduleA = {
state: {},
mutations: {},
actions: {},
getters: {}
}
const moduleB = {
state: {},
mutations: {},
actions: {}
}
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
结合示例讲解这5个核心,示例的展示效果如下:
创建store:在项目【src】目录下新建文件夹【store】及【store】下新建文件【index.js】。初始化state对象,getters,mutations,actions。
state---单一状态树,一个对象就包含了全部的应用层级状态,唯一的数据源。数据定义如下:
state: {
informations: [
{ name: "Lucy", age: 18 },
{ name: "Mike", age: 19 },
{ name: "Stanfen", age: 22 },
{ name: "Alice", age: 30 }
]
}
在组件的computed中通过【this.$store.state.informations】获取状态对象。
computed: {
informations() {
return this.$store.state.informations;
}
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性。
computed: {
...mapState(["informations"]),
}
getter---可以认为是store的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters: {
changeinfo: (state) => {
var changeinfo = state.informations.map(information => {
return {
name: "*" + information.name + "*",
age: information.age + 1
};
});
return changeinfo;
}
}
访问方式在组件的computed中通过【this.$store.getters.changeinfo】属性访问
computed: {
changeinfo() {
return this.$store.getters.changeinfo;
}
},
或者使用mapGetters辅助函数帮助我们生成计算属性。
computed: {
...mapGetters(["changeinfo"])
}
mutation---更改 Vuex 的 store 中的状态的唯一方法是提交 mutation(这句话来自官网,目前有些疑惑。)
开启严格模式,仅需在创建 store 的时候传入 strict: true;
const store = new Vuex.Store({
// ...
strict: true
})
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
mutations: {
addAge: state => {
state.informations.forEach(information => {
information.age += 1;
})
}
}
在组件的methods中通过【this.$store.commit("addAge");】提交mutation。
methods: {
addAge() {
this.$store.commit("addAge");
}
},
可以向【this.$store.commit("addAge");】传入载荷payload,即传入一个参数【this.$store.commit("addAge",2);】。
mutations: {
addAge: (state, payload) => {
state.informations.forEach(information => {
information.age += payload;
})
}
}
methods: {
addAge() {
this.$store.commit("addAge", 2);
}
}
action---处理异步操作。由于mutation都是同步事务,在 mutation 中混合异步调用会导致你的程序很难调试。Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。
mutations: {
addAge: (state, payload) => {
state.informations.forEach(info => {
info.age += payload;
})
}
},
actions: {
addAge: (context, payload) => {
setTimeout(function () {
context.commit("addAge", payload);
}, 2000);
}
}
在组件的methods中能够通过【this.$store.dispatch("addAge", 2);】分发action。
methods: {
addAge() {
this.$store.dispatch("addAge", 2);
}
},
或者使用mapActions辅助函数将组件的 methods 映射为 store.dispatch 调用
methods: {
...mapActions(["addAge"])
},
module---解决应用复杂的情况。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
在【main.js】中注册store
import Vue from 'vue'
import App from './App'
import { store } from './store/index.js'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
store: store,
el: '#app',
components: { App },
template: '<App/>'
})
在【App.vue】中注册子组件【PageOne.vue】【PageTwo.vue】
<template>
<div id="app">
<page-one></page-one>
<page-two></page-two>
</div>
</template>
<script>
import PageOne from "./components/PageOne";
import PageTwo from "./components/PageTwo";
export default {
name: "App",
data() {
return { };
},
components: {
"page-one": PageOne,
"page-two": PageTwo
}
};
</script>
子组件【PageOne.vue】
<template>
<div class="page-one">
<h3>组件1【vuex】- 中间状态管理</h3>
<ul>
<li v-for="information in changeinfo" :key="information">
<span class="name">{{information.name}}</span>
<span class="age">{{information.age}}</span>
</li>
</ul>
<button @click="addAge(2)">涨两岁</button>
</div>
</template>
<script>
import { mapState } from "vuex";
import { mapGetters } from "vuex";
import { mapActions } from "vuex";
export default {
computed: {
// informations() {
// return this.$store.state.informations;
// },
...mapState(["informations"]),
...mapGetters(["changeinfo"])
// changeinfo() {
// return this.$store.getters.changeinfo;
// }
},
methods: {
...mapActions(["addAge"])
// addAge() {
// this.$store.commit("addAge");
// this.$store.dispatch("addAge", 2);
// }
},
name: "page-one"
// props: ["informations"],
// data() {
// return {};
// }
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.page-one {
background: #fff8b1;
box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.2);
margin-bottom: 30px;
padding: 10px 20px;
width: 50%;
margin: 0px auto;
}
.page-one ul {
padding: 0;
}
.page-one li {
display: inline-block;
margin-right: 10px;
margin-top: 10px;
padding: 20px;
background: rgba(255, 255, 255, 0.7);
}
.age {
font-weight: bold;
color: #e8800c;
}
</style>
【PageTwo.vue】
<template>
<div class="page-two">
<h3>组件2【vuex】- 中间状态管理</h3>
<ul>
<li v-for="information in changeinfo" :key="information">
<span class="name">{{information.name}}</span>
<span class="age">{{information.age}}</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "page-two",
computed: {
informations() {
return this.$store.state.informations;
},
changeinfo() {
return this.$store.getters.changeinfo;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.page-two {
background: #d1e4ff;
box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.2);
margin-bottom: 30px;
padding: 10px 20px;
width: 50%;
margin: 20px auto;
}
.page-two ul {
padding: 0;
list-style-type: none;
}
.page-two li {
margin-right: 10px;
margin-top: 10px;
padding: 20px;
background: rgba(255, 255, 255, 0.7);
}
.age {
font-weight: bold;
color: #860ce8;
display: block;
}
</style>