Vuex概述

组件之间共享数据的方式

  • 父传子:v-bind 属性绑定
  • 子传父:v-on 事件绑定
  • 兄弟传值:EventBus
  • $on :接受数据的组件
  • $emit :发送数据的组件

    Vuex是什么

  • Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享

    使用 Vuex 统一管理状态的好处

  • 能够在 Vuex 中集中管理共享的数据,易于开发和后期维护

  • 能够高效地实现组件之间的数据共享,提高开发效率
  • 存储在 Vuex 中的数据都是响应式的,能够实时保持数据与页面的同步

    什么数据适合存储到 Vuex 中

  • 一般情况下,只有组件之间共享的数据,才有必要存储到 Vuex 中

  • 对于组件中的私有数据,依旧存储在组件自身的 data 中即可

    Vuex 的基本使用

    安装和使用 vuex 依赖包

  1. 安装 vuex 依赖包

    1. npm install vuex --save
  2. 导入 vuex 包

    1. import Vuex from 'vuex'
    2. Vue.use(Vuex)
  3. 创建 store 对象

    1. const store = new Vuex.Store({
    2. // state 中存放的就是全局共享的数据
    3. state: { count: 0 }
    4. })
  4. 将 store 对象挂载到 vue 实例中

    1. new Vue({
    2. el: '#app',
    3. render: h => h(app),
    4. router,
    5. // 将创建的共享数据对象,挂在到 Vue 实例中
    6. // 所有的组件,就可以直接从 store 中获取全局的数据了
    7. store
    8. })

    创建 vuex 项目

  5. 找到需要创建项目的文件夹目录,在该目录下打开 cmd 命令窗口,输入 vue ui 命令

image.png

  1. 点击创建项目按钮,然后输入依照以下内容进行填写

image.png

  1. 安装预设选择 手动配置, 功能如下:
    1. Choose Vue version
    2. Babel
    3. Vuex
    4. Router
    5. Linter / Formatter
    6. Use config files
  2. 配置文件选择

image.png

State

在 Vue 组件中获得 Vuex 状态

store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:

  1. // 创建一个 State.vue 组件
  2. <template>
  3. <div>
  4. <h1>名字:{{ name }}</h1>
  5. <h2>年龄:{{ age }}</h2>
  6. <h3>数量:{{ num }}</h3>
  7. <input type="text" v-model="num">
  8. </div>
  9. </template>
  10. <script>
  11. // state 在组件中的应用
  12. export default {
  13. computed: {
  14. name () {
  15. return this.$store.state.name
  16. },
  17. age () {
  18. return this.$store.state.age
  19. },
  20. num: {
  21. get () {
  22. return this.$store.state.num
  23. },
  24. set (val) {
  25. this.$store.commit('setNumber', val)
  26. }
  27. }
  28. }
  29. }
  30. </script>
  1. // router/index.js
  2. // 导入 State.vue 组件
  3. import State from '../view/State.vue'
  4. // 将 State.vue 组件挂在到 router/index.js 文件夹下
  5. { path: '/state', component: 'State' }
  1. // store/index.js
  2. import Vue from 'vue'
  3. import Vuex from 'vuex'
  4. Vue.use(Vuex)
  5. // 创建整个项目的数据仓库对象,将多组件共用的数据对象放置到此对象里
  6. export default new Vuex.Store({
  7. // data
  8. state: {
  9. name: 'JiangChen',
  10. age: 18,
  11. num: 0
  12. },
  13. // methods, 在 mutation 里处理状态
  14. mutations: {
  15. addNumber (state) {
  16. state.num += 2
  17. },
  18. setNumber (state, value) {
  19. state.num = value
  20. }
  21. }
  22. })

mapState 辅助函数

  • 当一个组件需要获取多个状态时,将这些状态声明为计算属性会有些重复和冗余。

    1. // 导入 mapState
    2. import { mapState } from 'vuex'
  • mapState 映射方法1(数组)

    1. <input type="text" :value="num" @input="changeValue">
    1. export default {
    2. computed: mapState(['name', 'age', 'num']),
    3. methods: {
    4. changeValue (e) {
    5. this.$store.commit('setNumber', e.target.value)
    6. }
    7. }
    8. }
  • mapState 映射方法2

    1. <input type="text" :value="num" @input="changeValue">
    1. export default {
    2. computed: mapState({
    3. // 对象方式
    4. name: 'name',
    5. // 箭头函数方式
    6. age: (state)=>state.age,
    7. num: 'num'
    8. })
    9. }
  • mapState 映射方法3 ```javascript let mapStateObj = mapState({ // 对象方式 name: ‘name’, // 箭头函数方式 age: (state)=>state.age, num: ‘num’ })

export default { computed: { reverse () { return this.name.split(‘ ‘).reverse().join(‘’) }, …mapStateObj } }

  1. <a name="HDDjB"></a>
  2. # Getter
  3. <a name="ppZHB"></a>
  4. ## 在Vuex中通过方法访问Getters状态
  5. 从 **store** 实例中读取状态最简单的方法就是在**计算属性**中返回某个状态:
  6. ```vue
  7. // 创建一个 Getter.vue 组件
  8. <template>
  9. <div>
  10. <h1>{{ $store.getters.reverseName }}</h1>
  11. <h2>{{ reverseName }}</h2>
  12. </div>
  13. </template>
  14. <script>
  15. export default {
  16. mounted () {
  17. console.log(this);
  18. },
  19. computed: {
  20. reverseName () {
  21. return this.$store.getters.reverseName
  22. }
  23. }
  24. }
  25. </script>
  1. // router/index.js
  2. // 导入 Getter.vue 组件
  3. import Getter from '../view/Getter.vue'
  4. // 将 Getter.vue 组件挂在到 router/index.js 文件夹下
  5. { path: '/getter', component: 'Getter' }
  1. // store/index.js
  2. import Vue from 'vue'
  3. import Vuex from 'vuex'
  4. Vue.use(Vuex)
  5. // 创建整个项目的数据仓库对象,将多组件共用的数据对象放置到此对象里
  6. export default new Vuex.Store({
  7. // 状态
  8. getters: {
  9. reverseName (state) {
  10. return state.name.split('').reverse().join('')
  11. },
  12. minin (state) {
  13. return '123' + state.name
  14. }
  15. }
  16. })

mapGetters 辅助函数

  1. // 导入 mapGetters
  2. import { mapGetter } from 'vuex'
  • mapGetters 方法1:

    1. export default {
    2. computed: mapGetters(['reverseName', 'mixinName'])
    3. }
  • mapGetter 方法2: ```javascript import {mapGetters, mapState} from ‘vuex’ let mapGetData = mapGetters([‘reverseName’, ‘mixinName’]); let mapStateData = mapState([‘name’, ‘age’, ‘num’])

export default { computed: { …mapGetData, …mapStateData } }

  1. - mapGetter 方法3
  2. ```html
  3. <!-- Getter.vue -->
  4. <h3>{{ mixinName1 }}</h3>
  1. // Getter.vue
  2. computed: {
  3. ...mapGetData,
  4. ...mapStateData,
  5. mixinName1() {
  6. return this.$store.getters.mixinName('666')
  7. }
  8. }
  1. // store/index.js
  2. // 状态
  3. getters: {
  4. mixinName (state) {
  5. return (val) => {
  6. return state.name + val
  7. }
  8. }
  9. }

Mutation

  • 触发事件是同步的,没有异步

    提交载荷(Payload)

    载荷当作参数传入

  • 向 mutation 中的方法提交第二个参数

    1. // Home.vue
    2. <button @click="setAction">setAction</button>
    1. // store/index.js
    2. mutations: {
    3. setNumber (state, value) {
    4. state.num += value
    5. }
    6. }
  • 在 Home.vue 组件中添加 setAction 方法,在方法内部调用 mutations 对象中的 setNumber 方法,并传入对应的参数

    setAction 可以改成任意名字

  1. // Home.vue
  2. methods: {
  3. setAction () {
  4. this.$store.commit('setNumber', 5)
  5. }
  6. }

载荷当作对象使用

  1. <button @click="autoAction">autoAction</button>
  1. // store/index.js
  2. mutations: {
  3. autoNumber (state, payload) {
  4. state.num += payload.amount
  5. }
  6. }
  • 在 Home.vue 组件中添加 autoAction 方法,在方法内部调用 mutations 对象中的 autoNumber 方法,并传入对应的参数

    autoAction 可以改成任意名字

  1. methods: {
  2. autoAction () {
  3. this.$store.commit('autoNumber', {
  4. amount: 3
  5. })
  6. }
  7. }

将方法当作对象传入

  1. <button @click="typeAction">typeAction</button>
  1. // store/index.js
  2. mutations: {
  3. typeNumber (state, payload) {
  4. state.num += payload.amount
  5. }
  6. }
  • 在 Home.vue 组件中添加 typeAction 方法,在方法内部调用 mutations 对象中的 typeNumber 方法,并传入对应的参数

    typeAction 可以改成任意名字

  1. methods: {
  2. typeAction () {
  3. this.$store.commit('autoNumber', {
  4. amount: 8
  5. })
  6. }
  7. }

在组件中提交 Mutation(mapMutations 辅助函数)

  1. <h1>{{ num }}</h1>
  2. <button @click="autoNumber({amount: 5})">autoNumber</button>
  1. // About.vue 组件中导入 mapMutations, mapState
  2. import { mapMutations, mapState } from 'vuex'
  3. let mapStateObj = mapState(['name', 'age', 'num', 'duanzi'])
  4. let mapMutationsObj = mapMutations(['addNumber', 'setNumber','autoNumber', 'typeNumber'])
  5. export default {
  6. computed: {
  7. ...mapStateObj
  8. },
  9. methods: {
  10. ...mapMutationsObj
  11. }
  12. }
  1. // store/index.js
  2. export default new Vuex.Store({
  3. // data
  4. state: {
  5. name: 'JiangChen',
  6. age: 18,
  7. num: 0,
  8. duanzi: null
  9. },
  10. // 异步方法
  11. actions: {
  12. setDz (content) {
  13. let httpUrl = 'https://api.apiopen.top/getJoke?page=1&count=10&type=text';
  14. fetch(httpUrl).then(res => res.json()).then(res => {
  15. console.log(res)
  16. console.log(content);
  17. // 通过 muation 来设置 state
  18. content.commit('setDuanzi', res.result)
  19. })
  20. }
  21. }
  22. })

Action

  • 可以包含任何异步操作
  • store/index.js 中,使用 content 代替 state
  • 组件中,使用 dispatch 调用

    分发Action

    ```html

  • {{ item.text }}

  1. ```javascript
  2. // Action.vue 组件中
  3. export default {
  4. methods: {
  5. getDuanzi () {
  6. this.$store.dispatch('setDz')
  7. }
  8. }
  9. }
  1. // store/index.js
  2. export default new Vuex.Store({
  3. actions: {
  4. setDz (content) {
  5. let httpUrl = 'https://api.apiopen.top/getJoke?page=1&count=10&type=text';
  6. fetch(httpUrl).then(res => res.json()).then(res => {
  7. console.log(res)
  8. console.log(content);
  9. // 通过 muation 来设置 state
  10. content.commit('setDuanzi', res.result)
  11. })
  12. }
  13. }
  14. })

mapActions 辅助函数

  1. <button @click="setDz">setDz</button>
  2. <ul style="text-align: left;">
  3. <li v-for="(item, index) in duanzi" :key="index">{{ item.text }}</li>
  4. </ul>
  1. // Action.vue 组件中
  2. import { mapState, mapActions } from 'vuex'
  3. let mapStateObj = mapState(['duanzi'])
  4. let mapActionsObj = mapActions(['setDz'])
  5. export default {
  6. computed: {
  7. ...mapStateObj
  8. },
  9. methods: {
  10. ...mapActionsObj
  11. }
  12. }
  1. // store/index.js
  2. export default new Vuex.Store({
  3. // data
  4. state: {
  5. name: 'JiangChen',
  6. age: 18,
  7. num: 0,
  8. duanzi: null
  9. },
  10. // 异步方法
  11. actions: {
  12. setDz (content) {
  13. let httpUrl = 'https://api.apiopen.top/getJoke?page=1&count=10&type=text';
  14. fetch(httpUrl).then(res => res.json()).then(res => {
  15. console.log(res)
  16. console.log(content);
  17. // 通过 muation 来设置 state
  18. content.commit('setDuanzi', res.result)
  19. })
  20. }
  21. }
  22. })

Modules

将 store/index.js 文件中的所有模块全部使用模块化的方式导入

  1. // store/index.js
  2. import state from './state'
  3. import getters from './getters'
  4. import mutations from './mutations'
  5. import actions from './actions'
  6. import buyCar from './buyCar'
  7. export default new Vuex.Store({
  8. // data
  9. state,
  10. // 状态
  11. getters,
  12. // methods, 在 mutation 里处理状态
  13. mutations,
  14. // 异步方法
  15. actions,
  16. // 模块
  17. modules: {
  18. buyCar
  19. }

使用模块化

  1. // BuyCar.vue
  2. <h2 style="color: aqua;">{{ $store.state.buyCar.productNum }}</h2>
  3. <h3>{{ buyCar.productNum }}</h3>
  4. <h4>{{ brief }}</h4>
  5. <button @click="addProNum">addProNum</button><br><br>
  6. <button @click="changeProNum">changeProNum</button>
  1. // BuyCar.vue
  2. import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
  3. let mapStateObj = mapState(['buyCar'])
  4. let mapGettersObj = mapGetters(['brief'])
  5. let mapMutationsObj = mapMutations(['addProNum'])
  6. let mapActionsObj = mapActions(['changeProNum'])
  7. export default {
  8. mounted () {
  9. console.log(this);
  10. },
  11. computed: {
  12. ...mapStateObj,
  13. ...mapGettersObj
  14. },
  15. methods: {
  16. ...mapMutationsObj,
  17. ...mapActionsObj
  18. }
  19. }