##vuex
可以用于解决不同组件之间数据的共享问题。
可以把多个页面需要的属性存放到vuex当中。
##vuex 五个核心属性
state【在computed里面调用】
state 可以理解为组件中的data,但是组件当中的data是一个局部的数据仓库,而state是一个全局的数据仓库,只要数据存放在state里面,任何组件都可以访问它的数据。
一般我们都是用计算属性来接受vuex里面的数据;
通过 this.$store.state.carLi st 来获取state里面的数据。
<template>
<div>
//这是商品详情页面
<ul>
<li v-for="(item,index) in list" :key="index">
ID:{{item.id}}
名称:{{item.name}}
数量:{{item.num}}
价格:{{item.price}}
</li>
</ul>
</div>
</template>
list(){
return this.$store.state.list;
}
},
created() {
console.log(this.$store.state.carList);
},
mutations【在methods里面调用】
mutations 可以理解为全局的方法,跟组件当中的methods类似;定义在组件当中的methods是局部方法;定义在mutations里面的方法可以被任何组件所访问。
如果想要修改state当中的数据,需要在mutations里面修改,这是vuex的一个规范。
下面是一个不规范的示例:
methods:{ **//** **在** **methods** **里面提交** **mutations** **里面的方法**
change(){
this.$store.state.name = '李四'; //可以,但是不推荐
}
}
可以直接修改全局数据仓库里面的属性,修改之后的属性会同步传递到其他组件中去,但是不推荐用这种方式去直接修改数据仓库里面的属性
规范示例:
//推荐用mutations里面的方法去进行修改
this.$store.commit("upts"); //不穿值
this.$store.commit("upts","赵六"); //传递值(赵六)给mutations
this.$store.commit("upts",{username:"王九",age:"13"}) //传递多个值,要组合成对象或者数组的形式,因为载荷只能接受一个参数
actions【在methods里面调用】
可以理解为全局的方法,跟组件当中的methods类似。它跟mutations的区别是:mutations里面写的方法是一个同步方法,而actions里面写的方法可以是同步,也可以是异步。
通过actions解决了mutations异步操作导致的VUE调试工具与页面所展示的数据不一致的问题。如果在mutations里面书写异步操作,调试工具将不能检测到数据的变化。
正确做法:在actions里面执行mutations里面的同步方法。
通过 this.$store.dispatch("changeSync",val) 来调用actions里面的方法。val是传递给actions的参数,dispatch叫做分发;
actions:{
//1、如果在mutations里面书写异步操作,调试工具将不能检测到数据的变化
changeSync(context,val){//context是上下文对象,也可以理解为store;context对象里面可以获取到getters或者state的数据,或者执行mutations里面的方法
// console.log(context);
//2、此时虽然异步操作写在了actions里面,但是调试工具依然不能检测到数据的变化
// setTimeout(function(){
// let item = context.state.list.find(ete => ete.id == val.id); //find()方法是javascript内置方法
// item.num--;
// if(context.state.carList.some(ete => ete.id == val.id)){
// let carItem = context.state.carList.find(ete => ete.id == val.id);
// carItem.num++;
// }else{
// let obj = {
// id: val.id,
// name: val.name,
// num: 1,
// price: val.price ,
// isChecked: false,
// };
// context.state.carList.push(obj);
// }
// },1000)
**//** **正确做法:在** **actions** **里面提交** **mutations** **里面的方法**
setTimeout(() => {
context.commit("change",val);
},1000);
}
},
<template>
<div>
这是商品详情页面
<ul>
<li v-for="(item,index) in list" :key="index">
ID:{{item.id}}
名称:{{item.name}}
数量:{{item.num}}
价格:{{item.price}}
<button @click="add(item)" :disabled="item.num == 0">添加</button> <!--当商品数量为0时禁用-->
<button @click="addSync(item)">异步添加</button>
</li>
</ul>
</div>
</template>
<script>
export default {
computed: {//一般我们都是用计算属性来接受vuex里面的数据
list(){
return this.$store.state.list;
}
},
created() {
console.log(this.$store.state.carList);
},
methods: { **//** **在** **methods** **里面调用** **actions** **里面的方法**
add(val){//执行mutations里面的change方法,来改变state的数据
this.$store.commit("change",val); //val是传递给mutations的参数
},
addSync(val){//通过this.$store.dispatch("changeSync")来调用actions里面的方法
this.$store.dispatch("changeSync",val); ////val是传递给actions的参数
},
},
};
</script>
<style scoped lang="scss"></style>
getters【在computed里面调用】
类似与computed,用于监听vuex里state的数据变化,用法跟计算属性的用法一致
computed: {
list(){
return this.$store.state.carList;
},
getPrice(){
return this.$store.getters.total;
},
// isAllchecked(){
// return this.$store.getters.isAllchecked;
// },
//要更改计算属性的值,一定要写成对象形式
isAllchecked:{
get(){
return this.$store.getters.isAllchecked;
},
set(val){
this.$store.commit("uptChecked",val);
}
},
},
modules
将store文件夹中的index.js分模块(例如:和登陆有关的数据、方法等就放在login.js中)。
那么如何在其他组件引用modules里面分模块的数据呢?
首先要在store文件夹的index.js中引入它:
【store/index.js】
import login from './modules/login.js' //引入login.js
import num from './modules/num.js' //引入num.js
import rmb from './modules/myToRMB.js' //引入myToRMB.js
export default new Vuex.Store({
modules:{
moduleA: login,
moduleB: num,
moduleC: rmb,
},
state:{},
mutations:{},
actions:{},
getters:{},
})
如何调用modules模块里面的state、mutations、actions、getters
分为两种方式:
1. 用普通方法调用
2. 用vuex辅助函数调用
- 普通方法调用
state
this.$store.state.moduleA.username // 在调用的时候加上了模块名称
mutations
this.$store.commit("uptUserName") // 调用的时候没有加上对应的模块名称
getters
this.$store.getters["moudleRmb/rmb"]
actions
this.$store.dispatch("moduleB/increaseSync");
namespaced: true
代表开启命名空间. 默认获取state里面的数据时,前面要加上模块名称;而mutations、actions、getters不用加模块名称,但是当加上命名空间之后,必须要加上相对应的模块名称。
如果没有开启命名空间,会发生什么?
this.$ store.commit("uptNum ") // 执行此方法时,login.js和num.js里面两个同名的uptNum方法都会执行
2) 用vuex辅助函数调用
###mapState
1. 使用辅助函数获取state里面的数据
注意点:
数组的方式不行:...mapState(["listModule/carList","num"])
对象字符串的方式不行:...mapState({list:"listModule/carList"})
正确的做法:要用函数形式获取模块state里面的数据
...mapState({
list:function(state){
return state.listModule.carList;
}
}),
###mapGetters
2. 使用辅助函数获取getters里面的数据
...mapGetters({allChecked:"listModule/isAllChecked"})
###mapMutations
3. 使用辅助函数获取mutations里面的数据
methods:{
...mapMutations({
decs:"listModule/dec"
})
}
###mapActions
4. 使用辅助函数获取mapActions里面的数据
...mapActions({
inc:"listModule/syncAdd"
})
【 modules/num.js 】
**var num = {**
**namespaced: true, //** **代表开启命名空间** **.** **默认获取** **state** **里面的数据时,前面要加上模块名称** **,** **而** **mutations** **、** **actions** **、** **getters** **不用加模块名称,但是当加上命名空间之后,必须要加上相对应的模块名称**
**state: {**
**num: 1 //this.$store.state.moduleA.num**
**},**
**actions: {**
**increaseSync(context){//this.$store.dispatch("moduleB/increaseSync")**
**console.log(context);**
**//** **在异步操作里面调用同步操作**
**setTimeout(()=>{**
**context.commit("increase")**
**},1000)**
**},**
**},**
**mutations: {**
**uptNum(state){ //this.$store.commit("moduleB/uptNum")**
**state.num += 4**
**},**
**increase(state){**
**state.num++;**
**},**
**decrease(state){**
**state.num--;**
**},**
**},**
**getters: {}**
**}**
**export default num;**
<template>
<div class="about">
<h1>辅助函数</h1>
<p>{{num}} {{name}}</p>
<p>这里是当前组件的area:{{area}}</p>
<p>这里是vuex里面的area:{{areas}}</p>
<p>{{area1}}</p>
<p>{{area2}}</p>
<p>
请输入美元:
<input type="text" v-model="my" @input="changes">
</p>
<p>转换之后的结果:{{rmb}}</p>
<p>moduleA里面的数据:{{moduleANum}}</p>
<p>moduleB里面的数据:{{moduleBNum}}</p>
<button @click="upts">点击</button>
</div>
</template>
<script>
//我们用vuex的辅助函数时,首先要先引入它
import { mapState,mapMutations } from "vuex";
export default{
methods:{
// ...mapMutations({
// uptMy : "uptMy"
// }),
changes(){
// this.uptMy(this.my);
this.$store.commit("moduleRmb/uptMy",this.my);
},
upts(){
// this.$store.commit("uptNum") //**这里没有开启命名空间时,执行的方式,此时** **login.js** **和** **num.js** **里面两个同名的** **uptNum** **方法都会执行**
this.$store.commit("moduleA/uptNum") //开启命名空间之后,可以用这种方式只执行模块A也就是login.js里面的uptNum
}
},
data(){
return {
area:"郑州",
my: 10,
}
},
computed:{
moduleANum(){
return this.$store.state.moduleA.num;
},
moduleBNum(){
return this.$store.state.moduleB.num;
},
rmb(){
return this.$store.getters["moduleRmb/rmb"];
},
// num(){
// return this.$store.state.num;
// },
//等价于上面的num方法
...mapState(["num","name"]), //当然它把name数据也搞过来了,而上面没有
//**vuex** **里面的数据和当前组件数据同名时,如果想要获得** **vuex** **里面的数据得要用对象的形式给它取一个别名**
...mapState({
areas:"area" //字符串方式获取state里面的数据
}),
//函数方式获取state里面的数据
//通过函数形式的好处是:可以将本地组件的数据和vuex里面的数据结合起来用
area1:function(state){
if(!this.area){//如果本地组件不存在area数据,则返回vuex里面的area,否则返回本地组件里面的数据
return state.area;
}else{
return this.area;
}
},
area2:(state) => {
console.log(this); //undefined
return state.area;
}
},
}
</script>
vuex 辅助函数(四个),帮助我们节省代码的语法糖:
- mapState
- mapGetters
- mapMutations
- mapActions**
mapState 和mapGetters放在computed计算属性里面;
mapActions 和mapMutations放在methods方法里面;
如何用呢?
【home.vue】
<script>
**//** **我们用** **vuex** **的辅助函数时,首先要先引入它**
import {mapState,mapActions,mapMutations,mapGetters} from "vuex";
export default{
methods:{
**// ...mapMutations({**
**// uptMy : "uptMy" //** **把** **mutations** **里面的方法搞过来**
**// }),**
changes(){
**// this.uptMy(this.my); //** **调用【** **this.my** **是传递过去的参数】**
this.$store.commit("moduleRmb/uptMy",this.my);
},
},
data(){
return {
area:"郑州",
my: 10,
}
},
computed:{
**// ...mapGetters({**
**// rmb: "rmb"**
**// }),**
// num(){
// return this.$store.state.num;
// },
//等价于上面的num方法
...mapState(["num","name"]),
//vuex里面的数据和当前组件数据同名时,如果想要获得vuex里面的数据得要用对象的形式给它取一个别名
...mapState({
areas:"area" //字符串方式获取state里面的数据
}),
},
}
</script>
<template>
<div class="home">
<!-- <button @click="incSync">异步+</button>-->
<button @click="increaseSync">异步+</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name: 'Home',
methods:{
**...mapActions({**
**increaseSync : "increaseSync"**
**}),**
**incSync(){**
**this.$store.dispatch("increaseSync");**
**},**
},
}
</script>
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import login from './modules/login.js' //引入login.js
import num from './modules/num.js' //引入num.js
import rmb from './modules/myToRMB.js'
export default new Vuex.Store({
modules: {//注册模块
moduleA: login,
moduleB: num,
moduleRmb: rmb,
},
state: {
num: 1,
area: "北京",
name: "张三",
my: ""
},
mutations: {
uptMy(state,val){
state.my = val;
},
/**
*
* @param {*} state
* @param {*} val
* 有两种调用方式
* 1.this.$store.commit("uptUsername")
* 2.辅助函数:mapMutations
*/
uptUsername(state,val){
state.username = val
},
},
actions: {
increaseSync(context){
console.log(context);
//在异步操作里面调用同步操作
setTimeout(()=>{
context.commit("increase")
},1000)
},
},
getters: {
rmb(state){
return state.my*7.0905;
}
},
})
```
vuex的缺陷:
当刷新页面之后,存储在vuex,state当中的数据就重新初始化了。
如果想要在vuex长久的存储数据,需要vuex与本地存储结合使用