Maison  >  Article  >  interface Web  >  Introduction à 8 façons de communiquer avec les composants Vue (Collection)

Introduction à 8 façons de communiquer avec les composants Vue (Collection)

青灯夜游
青灯夜游avant
2020-07-09 15:20:044007parcourir

Introduction à 8 façons de communiquer avec les composants Vue (Collection)

vue est un framework pour les mises à jour de vues basées sur les données, donc la communication de données entre les composants est très importante pour vue, alors comment la communication de données se produit-elle entre les composants ? Tout d'abord, nous devons savoir quel type de relation existe entre les composants dans Vue, afin qu'il soit plus facile de comprendre leurs méthodes de communication.

Explication des relations dans le composant vue :

Introduction à 8 façons de communiquer avec les composants Vue (Collection)

Comme le montre la figure ci-dessus, A et B, A et C, B et D, la relation entre les composants C et E est une relation père-fils ; la relation entre B et C est une relation entre A et D, et A et E est une relation générationnelle ; est un cousin (pas un parent immédiat). Pour les relations ci-dessus, nous La classe est :

  1. Communication entre les composants parent et enfant

  2. Communication entre les composants non parents et enfants (composants frères et sœurs, composants séparés par génération, etc.)

1. Le composant parent transmet les données au composant enfant via des accessoires, et les composants $emit Child peuvent communiquer avec les composants parents.

1. Le composant parent transmet la valeur au composant enfant

Comment le composant parent transmet les données au composant enfant : Comment obtenir le composant parent section.vue dans l'enfant composant article.vue Données dans les articles

// section父组件
<template>
 <p class="section">
 <com-article :articles="articleList"></com-article>
 </p>
</template>
<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { comArticle },
 data() {
 return {
 articleList: [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;,&#39;four&#39;,&#39;fives&#39;]
 }
 }
}
</script>
// 子组件 article.vue
<template>
 <p>
 <span v-for="(item, index) in articles" :key="index">{{item}}</span>
 </p>
</template>
<script>
export default {
 props: [&#39;articles&#39;]
}
</script>

Résumé : le prop ne peut être transmis que du composant de niveau supérieur au composant de niveau inférieur (composant parent-enfant), qui est ce que l'on appelle les données unidirectionnelles couler. De plus, prop est en lecture seule et ne peut pas être modifié. Toutes les modifications seront invalides et un avertissement sera émis.


2. Le composant enfant transmet la valeur au composant parent

Ma propre compréhension de $emit est la suivante : $emit lie un événement personnalisé, lorsque cette instruction est exécutée, le paramètre arg sera transmis au composant parent, et le composant parent écoute et reçoit les paramètres via v-on. À l'aide d'un exemple, expliquez comment le composant enfant transmet les données au composant parent. Sur la base de l'exemple précédent, cliquez sur l'élément d'article rendu par la page, et l'indice affiché dans le tableau du composant parent

// 父组件中
<template>
 <p class="section">
 <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
 <p>{{currentIndex}}</p>
 </p>
</template>
<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { comArticle },
 data() {
 return {
 currentIndex: -1,
 articleList: [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;,&#39;four&#39;,&#39;fives&#39;]
 }
 },
 methods: {
 onEmitIndex(idx) {
 this.currentIndex = idx
 }
 }
}
</script>
<template>
 <p>
 <p v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</p>
 </p>
</template>
<script>
export default {
 props: [&#39;articles&#39;],
 methods: {
 emitIndex(index) {
 this.$emit(&#39;onEmitIndex&#39;, index)
 }
 }
}
</script>
// 父组件中
<template>
 <p class="hello_world">
 <p>{{msg}}</p>
 <com-a></com-a>
 <button @click="changeA">点击改变子组件值</button>
 </p>
</template>
<script>
import ComA from &#39;./test/comA.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { ComA },
 data() {
 return {
 msg: &#39;Welcome&#39;
 }
 },
 methods: {
 changeA() {
 // 获取到子组件A
 this.$children[0].messageA = &#39;this is new value&#39;
 }
 }
}
</script>
// 子组件中
<template>
 <p class="com_a">
 <span>{{messageA}}</span>
 <p>获取父组件的值为: {{parentVal}}</p>
 </p>
</template>
<script>
export default {
 data() {
 return {
 messageA: &#39;this is old&#39;
 }
 },
 computed:{
 parentVal(){
 return this.$parent.msg;
 }
 }
}
</script>

doit faire attention aux conditions aux limites, telles que prendre $parent sur #app Ce que vous obtenez est une instance de new Vue(). Si vous prenez $parent sur cette instance, vous n'êtes pas défini, et si vous prenez $children sur le composant enfant du bas, c'est un tableau vide. Notez également que les valeurs de $parent et $children sont différentes. La valeur de $children est un tableau, tandis que $parent est un objet

Résumé

Les deux méthodes ci-dessus sont utilisées pour la communication entre parent et. Les composants enfants et les accessoires sont utilisés pour la communication. La communication entre composants parent-enfant est plus courante ; aucun des deux ne peut être utilisé pour la communication entre des composants non parent-enfant.

3. provide/injectConcept :

provide/inject est une nouvelle API dans vue2.2.0, simple En d’autres termes, la variable est fournie via provide dans le composant parent, puis la variable est injectée via inject dans le composant enfant.

Remarque : quelle que soit la profondeur d'imbrication du sous-composant ici, tant que inject est appelé, les données fournies dans provide peuvent être injectées, et cela ne se limite pas au renvoi de données à partir de l'attribut props du composant parent actuel


Vérifiez avec un exemple

Ensuite, utilisez un exemple pour vérifier la description ci-dessus : Supposons qu'il y ait trois composants : A.vue, B.vue, C.vue, où C est un sous-composant de B, et B est un sous-composant de A.

// A.vue
<template>
 <p>
	<comB></comB>
 </p>
</template>
<script>
 import comB from &#39;../components/test/comB.vue&#39;
 export default {
 name: "A",
 provide: {
 for: "demo"
 },
 components:{
 comB
 }
 }
</script>
// B.vue
<template>
 <p>
 {{demo}}
 <comC></comC>
 </p>
</template>
<script>
 import comC from &#39;../components/test/comC.vue&#39;
 export default {
 name: "B",
 inject: [&#39;for&#39;],
 data() {
 return {
 demo: this.for
 }
 },
 components: {
 comC
 }
 }
</script>
// C.vue
<template>
 <p>
 {{demo}}
 </p>
</template>
<script>
 export default {
 name: "C",
 inject: [&#39;for&#39;],
 data() {
 return {
 demo: this.for
 }
 }
 }
</script>

4. ref / refsref : Si utilisé sur un élément DOM normal, la référence pointe vers l'élément DOM ; si elle est utilisée Sur le sous-composant, la référence pointe vers l'instance du composant Vous pouvez appeler directement la méthode du composant ou accéder aux données via l'instance. Regardons un exemple d'accès au composant en utilisant ref :

// 子组件 A.vue
export default {
 data () {
 return {
 name: &#39;Vue.js&#39;
 }
 },
 methods: {
 sayHello () {
 console.log(&#39;hello&#39;)
 }
 }
}
// 父组件 app.vue
<template>
 <component-a ref="comA"></component-a>
</template>
<script>
 export default {
 mounted () {
 const comA = this.$refs.comA;
 console.log(comA.name); // Vue.js
 comA.sayHello(); // hello
 }
 }
</script>

5 , eventBuseventBus est également appelé event bus Il peut être utilisé comme concept de pont de communication en vue. C'est comme si tous les composants partageaient le même centre d'événements et pouvaient s'inscrire auprès du centre. Envoyer ou recevoir des événements, afin que les composants puissent notifier d'autres composants.

EventBus présente également des inconvénients. Lorsque le projet est volumineux, il peut facilement provoquer des catastrophes difficiles à maintenir.

Comment utiliser eventBus pour réaliser la communication de données entre les composants des projets Vue ? les étapes suivantes

1. Initialisation

Vous devez d'abord créer un bus d'événements et l'exporter afin que d'autres modules puissent l'utiliser ou le surveiller.

// event-bus.js
import Vue from &#39;vue&#39;
export const EventBus = new Vue()

2. Envoyer des événements

Supposons que vous ayez deux composants : additionNum et showNum. Ces deux composants peuvent être des composants frères ou des composants parent-enfant comme exemple : <.>

<template>
 <p>
 <show-num-com></show-num-com>
 <addition-num-com></addition-num-com>
 </p>
</template>
<script>
import showNumCom from &#39;./showNum.vue&#39;
import additionNumCom from &#39;./additionNum.vue&#39;
export default {
 components: { showNumCom, additionNumCom }
}
</script>
// addtionNum.vue 中发送事件
<template>
 <p>
 <button @click="additionHandle">+加法器</button> 
 </p>
</template>
<script>
import {EventBus} from &#39;./event-bus.js&#39;
console.log(EventBus)
export default {
 data(){
 return{
 num:1
 }
 },
 methods:{
 additionHandle(){
 EventBus.$emit(&#39;addition&#39;, {
 num:this.num++
 })
 }
 }
}
</script>


3. Recevez l'événement

// showNum.vue 中接收事件
<template>
 <p>计算和: {{count}}</p>
</template>
<script>
import { EventBus } from &#39;./event-bus.js&#39;
export default {
 data() {
 return {
 count: 0
 }
 },
 mounted() {
 EventBus.$on(&#39;addition&#39;, param => {
 this.count = this.count + param.num;
 })
 }
}
</script>
De cette façon, cliquez sur le bouton ajouter dans le composant additionNum.vue, dans showNum In vue, le numéro transmis est utilisé pour afficher le résultat de la sommation.

4. Supprimez l'écouteur d'événement

Si vous souhaitez supprimer l'écouteur d'événement, vous pouvez procéder comme suit. :

import { eventBus } from &#39;event-bus.js&#39;
EventBus.$off(&#39;addition&#39;, {})

6. Vuex

1. Introduction à Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

2、Vuex各个模块

state:用于数据的存储,是store中的唯一数据源
getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

3、Vuex实例应用

// 父组件
<template>
 <p id="app">
 <ChildA/>
 <ChildB/>
 </p>
</template>
<script>
 import ChildA from &#39;./components/ChildA&#39; // 导入A组件
 import ChildB from &#39;./components/ChildB&#39; // 导入B组件
 export default {
 name: &#39;App&#39;,
 components: {ChildA, ChildB} // 注册A、B组件
 }
</script>
// 子组件childA
<template>
 <p id="childA">
 <h1>我是A组件</h1>
 <button @click="transform">点我让B组件接收到数据</button>
 <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
 </p>
</template>
<script>
 export default {
 data() {
 return {
 AMessage: &#39;Hello,B组件,我是A组件&#39;
 }
 },
 computed: {
 BMessage() {
 // 这里存储从store里获取的B组件的数据
 return this.$store.state.BMsg
 }
 },
 methods: {
 transform() {
 // 触发receiveAMsg,将A组件的数据存放到store里去
 this.$store.commit(&#39;receiveAMsg&#39;, {
 AMsg: this.AMessage
 })
 }
 }
 }
</script>
// 子组件 childB
<template>
 <p id="childB">
 <h1>我是B组件</h1>
 <button @click="transform">点我让A组件接收到数据</button>
 <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
 </p>
</template>
<script>
 export default {
 data() {
 return {
 BMessage: &#39;Hello,A组件,我是B组件&#39;
 }
 },
 computed: {
 AMessage() {
 // 这里存储从store里获取的A组件的数据
 return this.$store.state.AMsg
 }
 },
 methods: {
 transform() {
 // 触发receiveBMsg,将B组件的数据存放到store里去
 this.$store.commit(&#39;receiveBMsg&#39;, {
 BMsg: this.BMessage
 })
 }
 }
 }
</script>
vuex的store,js
import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
Vue.use(Vuex)
const state = {
 // 初始化A和B组件的数据,等待获取
 AMsg: &#39;&#39;,
 BMsg: &#39;&#39;
}
const mutations = {
 receiveAMsg(state, payload) {
 // 将A组件的数据存放于state
 state.AMsg = payload.AMsg
 },
 receiveBMsg(state, payload) {
 // 将B组件的数据存放于state
 state.BMsg = payload.BMsg
 }
}
export default new Vuex.Store({
 state,
 mutations
})

 七、localStorage / sessionStorage

这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。 通过window.localStorage.getItem(key)获取数据 通过window.localStorage.setItem(key,value)存储数据

注意用JSON.parse() / JSON.stringify() 做数据格式转换 localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.

 八 $attrs与 $listeners

现在我们来讨论一种情况, 我们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?

  1. 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递

  2. 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低

  3. 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.

在vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上。接下来看一个跨级通信的例子:

// app.vue
// index.vue
<template>
 <p>
 <child-com1
 :name="name"
 :age="age"
 :gender="gender"
 :height="height"
 title="程序员成长"
 ></child-com1>
 </p>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
 components: { childCom1 },
 data() {
 return {
 name: "zhang",
 age: "18",
 gender: "女",
 height: "158"
 };
 }
};
</script>
// childCom1.vue
<template class="border">
 <p>
 <p>name: {{ name}}</p>
 <p>childCom1的$attrs: {{ $attrs }}</p>
 <child-com2 v-bind="$attrs"></child-com2>
 </p>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
 components: {
 childCom2
 },
 inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
 props: {
 name: String // name作为props属性绑定
 },
 created() {
 console.log(this.$attrs);
 // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长" }
 }
};
</script>
// childCom2.vue
<template>
 <p class="border">
 <p>age: {{ age}}</p>
 <p>childCom2: {{ $attrs }}</p>
 </p>
</template>
<script>
export default {
 inheritAttrs: false,
 props: {
 age: String
 },
 created() {
 console.log(this.$attrs); 
 // { "gender": "女", "height": "158", "title": "程序员成长指北" }
 }
};
</script>

总结

常见使用场景可以分为三类:
父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
兄弟组件通信: eventBus ; vuex
跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer