vuex----store状态管理

版权声明:本文为博主原创文章,喜欢的话,可以通知我后进行转载哦! https://blog.csdn.net/maidu_xbd/article/details/89140696

上篇介绍单一使用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>

猜你喜欢

转载自blog.csdn.net/maidu_xbd/article/details/89140696