# 数据共享

  我们在学习 vue 的时候,可以知道要想实现数据间的数据共享,常见的有下面的几种方式:

  • props 属性绑定
  • 自定义事件
  • 全局事件总线

  但我们发现:当开发大型单页面应用时,我们需要大范围、频繁的使用数据共享,上述的方案显然就力不从心了。

# 一、状态管理模式

  下面看看,在 vue 中的状态管理方案,

  • 单向数据流:就是我们从接触 vue 到现在采取的方案
  • 全局单例模式管理:vuex 的一种新的解决方案

# 1、单向数据流

示意图:

流程体验(代码)
new Vue({
  // state
  data() {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment() {
      this.count++
    }
  }
})

缺点:

答案

  当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏

  • 多个视图依赖于同一状态
  • 来自不同视图的行为需要变更同一状态

  虽然这些在视图较少的情况下,我们可以用前面的知识解决,但相关联的视图一旦多起来,那将变得不可维护。

# 2、全局单例模式 ✨

  为了解决上面单向数据流存在的问题,vue 官方设计例专门的状态管理库 Vuex。

它把组件的共享状态抽取出来,以一个全局单例模式管理

提示

  Vuex 使用单一状态树(SSOT),整个应用仅仅包含一个 store 实例(在 Pinia 中没有 Module,可以创建多个 store 实例),但它可以利用 Module 创建多个模块

示意图:

提示

  重点关注 vue 组件使用 Mutations 的两条路线

直接触发,或者通过 Actions 触发

  还要理解,StateActions、Mutation 间的本质区别

前者作为 computed,后者作为 methods

流程体验 ✍(代码)
  • store/index.js
const actions = {
  // up: ({ commit }) => commit('UP'),
  // down: ({ commit }) => commit('DOWN'),

  upIfOdd({ commit, state }) {
    if ((state.count + 1) % 2 === 0) {
      commit('UP')
    }
  },
  upAsync({ commit }) {
    return new Promise((resolve) => {
      setTimeout(() => {
        commit('UP')
        resolve()
      }, 2000)
    })
  }
}

const mutations = {
  UP(state) {
    state.count++
  },
  DOWN(state) {
    state.count--
  }
}

const state = {
  count: 0
}
  • 组件
<template>
  <div class="home">
    <h3>AboutWorld组件内容</h3>

    数字: {{ $store.state.count }}
    <br />
    数字: {{ count }}

    <br /><br />
    <button @click="upIfOdd">奇数时--> +1</button>
    <button @click="upAsync">延迟2秒--> +1</button>

    <br /><br />
    <button @click="UP">+1</button>
    <button @click="DOWN">-1</button>
  </div>
</template>

<script>
import { mapActions, mapMutations, mapState } from 'vuex'

export default {
  name: 'AboutWorld',
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapActions(['up', 'down', 'upIfOdd', 'upAsync']),
    ...mapMutations(['UP', 'DOWN'])
  }
}
</script>

官方案例:https://github.com/vuejs/vuex/tree/3.x/examples

提示

  Actions 就像一个餐厅服务员,小饭店不一定需要它。但是大饭店得需要他去做一些业务处理:客人订单管理(js 逻辑处理),通知饮料/蔬菜采购(Backend API)等

  像 ActionsMutationsState 等都是一个对象,它们由背后的大佬 store 操控着。示意图上是从宏观的角度看的(即 vue 组件 和 vuex 之间的关系)

  什么时候,什么数据要使用全局单例模式管理

答案

  当我们确定某些数据,可能会在多个视图中交叉使用的时候,我们就可以将这些数据放在 vuex 中。官方的说法就是:

  • 多个视图依赖于同一状态
  • 来自不同视图的行为需要变更同一状态

# 二、Vuex

# 1、简介

官方介绍:

Vuex (opens new window) 可以帮助我们管理共享状态(数据),并附带了更多的概念和框架。

概念:

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

效果演示:

使用范围 ✨:

  一般情况下,存储到 vuex 中的数据是组件间的共享数据;对于组件中私有数据,存储在组件自身的 data 中即可。

# 2、安装使用

# ① 安装

npm install vuex@3

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。

# ② 构建 store

  • store / index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex) // 插件注册成功(vue中能使用vuex了)

const actions = {}
const mutations = {}
const state = {}

// 大佬store产生了✍
export default new Vuex.Store({
  actions,
  mutations,
  state
})

# ③ 使用 vuex

  • 局部使用
<script>
import store from '../store/index'

export default {
  name: 'HomeView',
  created() {
    store.commit('increment')
    // 效果:
    console.log(store.state.count)
  }
}
</script>
  • 全局使用
// main.js
import store from './store/index'

new Vue({
  store, // store: store的简写
  render: (h) => h(App)
}).$mount('#app')
<script>
export default {
  name: 'AboutWorld',
  created() {
    this.$store.commit('increment')
    // 效果:
    console.log(this.$store.state.count)
  }
}
</script>

# 3、脚手架

  同创建 vue-router 路由一样,使用 vue-cli 创建 SPA 项目以后,会自动生成相关文件 😂,不用自己手动编写。

注意的是:在 vue-cli <= 2.x 的旧版本模板时,是没法一键配置 Vuex 的。

更新于 : 7/8/2024, 10:21:14 AM