15. 项目 [vuejs-13]:使用会话更新组件
[vuejs-13] 项目在 [vuejs-12] 项目的基础上进行了如下改动:HTML 表格显示的数组被定义在一个所有组件均可访问的 [session] 对象中。因此,这成为组件之间共享信息的一种方式。这一概念直接借鉴了 Web 会话的概念。我们通过插件方法,将该共享对象作为 [Vue.$session] 属性提供给各组件使用。
项目目录结构如下:

15.1. [session] 对象
所有组件共享的 [session] 对象在 [./session.js] 脚本中定义:
const session = {
// liste des simulations
get lignes() {
return this._lignes;
},
// génération de la liste des simulations
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 }
]
},
// suppression ligne n° index
deleteLigne(index) {
this._lignes.splice(index, 1);
}
}
// export de l'objet [session]
export default session;
15.2. [./plugins/pluginSession] 插件
[pluginSession] 脚本如下:
export default {
install(Vue, session) {
// ajoute une propriété [$session] à la classe vue
Object.defineProperty(Vue.prototype, '$session', {
// lorsque Vue.$session est référencé, on rend le 2ième paramètre [session] de la méthode [install]
get: () => session,
})
}
}
- 第 4 行:共享对象 [session] 将作为 [$session] 属性在所有组件中可用;
15.3. 主脚本 [main.js]
主脚本 [main.js] 如下所示:
// imports
import Vue from 'vue'
import App from './App.vue'
// plugins
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
// bootstrap
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
// session
import session from './session';
import pluginSession from './plugins/pluginSession'
Vue.use(pluginSession, session)
// configuration
Vue.config.productionTip = false
// instanciation projet [App]
new Vue({
name: "app",
render: h => h(App),
}).$mount('#app')
- 第 14–16 行:[pluginSession] 插件已集成到 [Vue.js] 框架中;
- 第 16 行之后,所有组件均可使用 [$session] 属性;
15.4. 主视图 [App]
[App] 视图现在如下所示:
<template>
<div class="container">
<b-card>
<!-- message -->
<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>
<!-- table HTML -->
<Table @updateTable="updateTable" :key="versionTable"/>
</b-card>
</div>
</template>
<script>
import Table from "./components/Table";
export default {
// nom
name: "app",
// composants
components: {
Table
},
// état interne
data() {
return {
// version table
versionTable: 1
};
},
// méthodes
methods: {
updateTable() {
// eslint-disable-next-line
console.log("App updateTable");
// incrément version table
this.versionTable++;
}
}
};
</script>
评论
- 第 9 行中的 [App] 视图不再管理由 [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>
<!-- empty list -->
<template v-if="lignes.length==0">
<b-alert show variant="warning">
<h4>Votre liste de simulations est vide</h4>
</b-alert>
<!-- reload button-->
<b-button variant="primary" @click="rechargerListe">Recharger la liste</b-button>
</template>
<!-- non-empty list-->
<template v-if="lignes.length!=0">
<b-alert show variant="primary" v-if="lignes.length==0">
<h4>Liste de vos simulations</h4>
</b-alert>
<!-- simulation table -->
<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 {
// état calculé
computed: {
lignes() {
return this.$session.lignes;
}
},
// état interne
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" }
]
};
},
// méthodes
methods: {
supprimerLigne(index) {
// eslint-disable-next-line
console.log("Table supprimerLigne", index);
// on supprime la ligne
this.$session.deleteLigne(index);
// on demande au composant parent de mettre à jour la vue
this.$emit("updateTable");
},
// rechargement de la liste affichée
rechargerListe() {
// eslint-disable-next-line
console.log("Table rechargerListe");
// on régènère la liste des simulations
this.$session.generateLignes();
// on demande au composant parent de mettre à jour la vue
this.$emit("updateTable");
}
}
};
</script>
注释:
- [rows] 属性(第 4、12、17 行)不再是由父组件设置的参数,而是 [Table] 组件的计算属性(第 30–32 行)。因此,[rows] 即为数组 [$session.rows](第 31 行);
- 第 49–56 行:[deleteRow] 方法会从 [$session.rows] 数组中移除一行。默认情况下,此删除操作不会改变 HTML 表格的显示。这是因为 [$session] 的元素不具备响应式特性:对其所做的更改不会反映在使用它们的组件中。 因此,[Table] 组件通过 [updateTable] 事件(第 55 行)请求其父组件重新生成它。我们看到,父组件随后会递增 [Table] 组件的 [:key] 属性以强制其重新生成;
- 第 58–65 行:[reloadList] 方法请求 [$session] 对象重新生成 [$session.rows] 数组。与之前的原因相同,默认情况下,对 [$session.list] 的此修改也不会改变 HTML 表格的显示。 因此,[Table] 组件通过 [updateTable] 事件(第 64 行)请求其父组件重新生成它。
15.6. 运行项目

我们得到了与 [vuejs-12] 项目中相同的结果。