15. 项目 [vuejs-13]:组件更新,使用会话
项目 [vuejs-13] 基于项目 [vuejs-12],并进行了以下修改:由表 HTML 显示的表格被定义在一个名为 [session] 的对象中,该对象为所有组件所共享。 因此,这是一种在组件之间共享信息的方式。该概念直接借鉴了 Web 会话的思路。我们采用插件方法,将该共享对象作为 [Vue.$session] 属性提供。
项目结构如下:

15.1. 对象 [session]
由所有组件共享的 [session] 对象在脚本 [./session.js] 中定义:
const session = {
// 模拟列表
get lignes() {
return this._lignes;
},
// 生成模拟列表
generateLignes() {
this._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 }
]
},
// 删除索引号为 n 的行
deleteLigne(index) {
this._lignes.splice(index, 1);
}
}
// 导出对象 [session]
export default session;
15.2. 插件 [./plugins/pluginSession]
脚本 [pluginSession] 如下:
export default {
install(Vue, session) {
// 向视图类添加属性 [$session]
Object.defineProperty(Vue.prototype, '$session', {
// 当引用 Vue.$session 被引用时,将方法 [install] 的第二个参数 [session] 渲染出来
get: () => session,
})
}
}
- 第 4 行:共享对象 [session] 将作为所有组件的 [$session] 属性提供;
15.3. 主脚本 [main.js]
主脚本 [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';
import pluginSession from './plugins/pluginSession'
Vue.use(pluginSession, session)
// 配置
Vue.config.productionTip = false
// 项目实例化[App]
new Vue({
name: "app",
render: h => h(App),
}).$mount('#应用程序')
- 第 14-16 行:插件 [pluginSession] 已集成到框架 [Vue.js] 中;
- 第16行之后,[$session]属性对所有组件可用;
15.4. 主视图 [App]
视图 [App] 现如下所示:
<template>
<div class="container">
<b-card>
<!-- 消息 -->
<b-alert show variant="success" align="center">
<h4>[vuejs-13] : mise à jour d'un composant, partage des données avec une session</h4>
</b-alert>
<!-- 表HTML -->
<Table @updateTable="updateTable" :key="versionTable"/>
</b-card>
</div>
</template>
<script>
import Table from "./components/Table";
export default {
// 名称
name: "app",
// 组件
components: {
Table
},
// 内部状态
data() {
return {
// 表版本
versionTable: 1
};
},
// 方法
methods: {
updateTable() {
// eslint-disable-next-line
console.log("App updateTable");
// 版本表递增
this.versionTable++;
}
}
};
</script>
注释
- 视图 [App] 不再管理第 9 行中组件 [Table] 显示的数组;
- 第 9 行:组件 [Table] 触发事件 [updateTable],该事件要求重新生成组件 [Table]。 实现此功能的一种方法是使用属性 [:key]。将该属性设为可修改值。每次修改该值时,组件 [Table] 都会被重新生成;
- 第 9 行:[:key] 属性的值即为第 27 行中的 [versionTable] 属性。 方法 [updateTable](第 33-38 行)负责重新生成第 9 行中的组件 [Table]。 为此,该方法会递增第37行组件[Table]的属性[:key]的值。随后,组件[Table]将自动重新生成;
15.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.$session.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.$session.deleteLigne(index);
// 请求父组件更新视图
this.$emit("updateTable");
},
// 重新加载显示的列表
rechargerListe() {
// eslint-disable-next-line
console.log("Table rechargerListe");
// 重新生成模拟列表
this.$session.generateLignes();
// 请求父组件更新视图
this.$emit("updateTable");
}
}
};
</script>
注释:
- 属性 [lignes](第 4、12、17 行)不再是父组件设定的参数,而是组件 [Table](第 30-32 行)的计算属性。 因此,[lignes] 即为数组 [$session.lignes](第 31 行);
- 第49-56行:方法[supprimerLigne]会从表[$session.lignes]中删除一行。默认情况下,此删除操作不会改变表HTML的显示。实际上, [$session]中的元素不具备响应性:对其的修改不会反映到使用它们的组件上。因此,[Table]组件会通过[updateTable]事件 (第 55 行)请求其父级重新生成它。我们看到,父组件随后会递增 [Table] 组件的 [:key] 属性,以强制其重新生成;
- 第 58-65 行:方法 [rechargerListe] 要求对象 [$session] 重新生成数组 [$session.lignes]。 与前文所述原因相同,默认情况下,对 [$session.liste] 的此项修改不会改变表 HTML 的显示。 因此,组件 [Table] 通过事件 [updateTable](第 64 行)请求其父级对其进行重新生成。
15.6. 项目执行

结果与项目 [vuejs-12] 相同。