Skip to content

17. 项目 [vuejs-15]:使用插件 [Vuex]

项目 [vuejs-15] 继承了项目 [vuejs-14],并使用了由 [Vuex] 生成的响应式对象 [session]。该项目的结构如下:

Image

17.1. 安装依赖项 [vuex]

Image

17.2. 脚本 [./session.js]

对象 [session] 变为如下:


// Vuex 插件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

// 会话是一个 Vuex 存储
const session = new Vuex.Store({
  state: {
    // 模拟列表
    lignes: []
  },
  mutations: {
    // 生成模拟列表
    generateLignes(state) {
      // eslint-disable-next-line no-console
      console.log("mutation generateLignes");
      // 正在初始化 [state.lignes]
      state.lignes =
        [
          { id: 3, marié: "oui", enfants: 2, salaire: 35000, impôt: 1200 },
          { id: 5, marié: "non", enfants: 2, salaire: 35000, impôt: 1900 },
          { id: 7, marié: "non", enfants: 0, salaire: 30000, impôt: 2000 }
        ];
      // eslint-disable-next-line no-console
      console.log(state.lignes);
    },
    // 删除索引第 n 行
    deleteLigne(state, index) {
      // eslint-disable-next-line no-console
      console.log("mutation deleteLigne");
      // 删除第 [index] 行
      state.lignes.splice(index, 1);
    }
  }
});
// 导出对象 [session]
export default session;

注释

  • 第 2-4 行:将插件 [Vuex] 集成到框架 [Vue] 中;
  • 第 7 行:会话变为 [Vuex.Store] 类型的对象;
  • 第8-11行:属性[state]包含应用程序[Vue]的共享状态。该属性对应用程序的所有组件均可见。 此处我们共享了模拟数组 [lignes](第 10 行);
  • 第12-35行:属性[mutations]汇集了用于修改对象[state]内容的方法;
  • 第14-26行:属性[generateLignes]是一个为属性[state.lignes]生成初始值的函数。此处它接受[state]作为参数。 第 18-23 行:属性 [state.lignes] 被初始化;
  • 第 28-35 行:属性 [deleteLigne] 是一个函数,用于从数组 [state.lignes] 中删除一行。其参数为:
    • [state],代表第8-11行的对象;
    • [index],即要删除的行号;
  • [mutations] 属性的函数始终将第 8 行 [state] 属性的对象作为第一个参数。后续参数由调用该变异操作的代码提供;
  • 第 37 行:导出对象 [session]

与之前的项目 [vuejs-13] 不同,这里我们不会使用插件来通过 [Vue.$session] 属性使会话对组件可见。

17.3. 主脚本 [./main.js]

主脚本的演变如下:


// 导入
import Vue from 'vue'
import App from './App.vue'

// 插件
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);

// Bootstrap
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

// 会话
import session from './session';

// 配置
Vue.config.productionTip = false

// 项目实例化[App]
new Vue({
  name: "app",
  // Vuex 存储的使用
  store: session,
  render: h => h(App),
}).$mount('#应用程序

注释

  • 第 14 行:导入会话;
  • 第23行:会话被传递到主视图中,作为名为[store]的属性(这是强制要求的)。借助插件[Vuex],该属性随后可通过[Vue.$store]属性供所有组件使用。 因此,当前配置与前一个项目非常相似:此前在组件中通过 [this.$session] 访问会话,现在则通过 [this.$store] 访问;

17.4. 主视图 [App]

主视图 [App] 的变化如下:


<template>
  <div class="container">
    <b-card>
      <!-- 消息 -->
      <b-alert show variant="success" align="center">
        <h4>[vuejs-14] : utilisation du plugin [Vuex]</h4>
      </b-alert>
      <!-- 表 HTML -->
      <Table />
    </b-card>
  </div>
</template>

<script>
import Table from "./components/Table";
export default {
  // 名称
  name: "app",
  // 组件
  components: {
    Table
  },
  // 生命周期
  created() {
    // 生成模拟表
    this.$store.commit("generateLignes");
  }
};
</script>

注释

  • 第 9 行:视图 [App] 使用组件 [Table],但不再接收来自该组件的事件,这是因为存储 [Vuex] 具有响应性
  • 第24-27行:在创建组件[App]之后,立即执行方法[created]。在此方法中,执行名为[generateLignes]的变体,该变体为模拟数组生成初始值。 请注意该语句的特殊语法。需要说明的是,[this.$store] 表示 [main.js] 中实例化视图的 [store] 属性:

// 视图实例化[App]
new Vue({
  name: "app",
  // Vuex 存储的使用
  store: session,
  render: h => h(App),
}).$mount('#app')

因此,表示法 [this.$store] 指代对象 [session]。随后编写 [this.$store.commit("generateLignes")] 以执行名为 [generateLignes] 的变体。该变体是一个函数;

17.5. 组件 [Table]

组件 [Table] 的演变过程如下:


<template>
  <div>
    <!-- 空列表 -->
    <template v-if="lignes.length==0">
      <b-alert show variant="warning">
        <h4>Votre liste de simulations est vide</h4>
      </b-alert>
      <!-- 刷新按钮-->
      <b-button variant="primary" @click="rechargerListe">Recharger la liste</b-button>
    </template>
    <!-- 非空列表-->
    <template v-if="lignes.length!=0">
      <b-alert show variant="primary" v-if="lignes.length==0">
        <h4>Liste de vos simulations</h4>
      </b-alert>
      <!-- 模拟表 -->
      <b-table striped hover responsive :items="lignes" :fields="fields">
        <template v-slot:cell(action)="row">
          <b-button variant="link" @click="supprimerLigne(row.index)">Supprimer</b-button>
        </template>
      </b-table>
    </template>
  </div>
</template>

<script>
export default {
  // 计算结果
  computed: {
    lignes() {
      return this.$store.state.lignes;
    }
  },
  // 内部状态
  data() {
    return {
      fields: [
        { label: "#", key: "id" },
        { label: "Marié", key: "marié" },
        { label: "Nombre d'enfants", key: "enfants" },
        { label: "Salaire", key: "salaire" },
        { label: "Impôt", key: "impôt" },
        { label: "", key: "action" }
      ]
    };
  },
  // 方法
  methods: {
    supprimerLigne(index) {
      // eslint-disable-next-line
      console.log("Table supprimerLigne", index);
      // 删除该行
      this.$store.commit("deleteLigne", index);
    },
    // 重新加载显示列表
    rechargerListe() {
      // eslint-disable-next-line
      console.log("Table rechargerListe");
      // 重新生成模拟列表
      this.$store.commit("generateLignes");
    }
  }
};
</script>

注释

  • 第 1-24 行中的 [template] 保持不变;
  • 第 30-32 行:计算属性 [lignes] 现使用 [Vuex] 中的 [store]
  • 第49-54行:要从表HTML中删除一行,需使用[Vuex]生成的[store]的变体[deleteLigne]。 将要删除的行(第53行)的编号[index]作为参数传入;
  • 第56-61行:为了用新列表重新加载表HTML,使用[Vuex]生成的[store]的变体[generateLignes]

17.6. Conclusion

项目 [vuejs-13][Vue.$session] 属性与项目 [vuejs-15][Vue.$store] 属性非常相似。它们的目标相同:在视图之间共享信息。 [store]对象的优势在于其具备响应性,而[session]对象则不具备。 但 [vuejs-14] 项目表明,通过在视图的响应式属性中复制 [session] 对象,可以轻松使其具备响应式特性。