Resuma siete métodos de comunicación entre componentes de Vue

Durante el proceso de desarrollo, siempre encontrará varias situaciones de comunicación entre componentes. Sin embargo, hay muchas formas de comunicarse entre componentes en Vue. Hoy he hecho un pequeño resumen. A continuación, echemos un vistazo a los métodos de comunicación:

1. accesorios / $ emitir

Este es uno de los métodos que solemos usar con más frecuencia. El componente principal A pasa datos al componente secundario a través de parámetros de accesorios. El componente secundario envía un evento (que lleva datos de parámetros) al componente principal a través de $emit. El componente principal escucha $ emit y triggers El evento obtiene los datos enviados por el componente secundario a sí mismo.

Sin más preámbulos, aquí tienes un ejemplo sencillo:

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    <!-- 通过props把值传给子组件 -->
    <son
     :text-from-father="text"
     @tell-father="tellMe"
    />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son,
  }
})
 
export default class father extends Vue {
  text:string = '我是父组件';
 
  执行子组件触发的事件
  tellMe(val: string) {
    //接受到子组件传过来的值
    console.log(val); //I am son
  }
}
</script>

Código de subcomponente:

<template>
  <div>
    <p>我是子组件</p>
    <div>父组件告诉我:{
   
   {textFromFather}}</div>
    <el-button @click="tellFather">发送文字给父组件</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son',
  components: {
  }
})
 
export default class son extends Vue {
  @Prop({
    default: ''
  })
  textFromFather !: string; //设置props属性值,得到父组件传递过来的数据
 
  tellFather() {
    //触发父组件中的事件,向父组件传值
    this.$emit('tell-father','I am son')
  }
}
 
</script>

El componente principal pasa datos al componente secundario y vincula un evento de indicación del padre a través de v-on para escuchar el evento desencadenante del componente secundario;

El subcomponente obtiene los datos de texto relevantes a través de accesorios y finalmente activa el evento tell-father a través de this.$emit para completar la comunicación.

 

二、$niños/$padre

Introducción oficial de $children: componentes secundarios directos de la instancia actual. Tenga en cuenta que $children no garantiza el orden ni responde.

 

Introducción oficial de $parent: la instancia principal de la instancia actual.

 

El valor obtenido a través de $children es una matriz, que es una colección de hijos directos. Respecto al hijo específico, hay un atributo _uid en el hijo. Puedes saber qué elemento es, cuál es el identificador único del elemento. $ El padre es un objeto.

 

Ahora que puede obtener la instancia del componente, puede llamar a las propiedades o métodos del componente para operar.

 

A continuación veremos cómo el código implementa la comunicación:

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    <children />
    <el-button @click="changeChildren">点击改变子组件值</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import children from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    children
  }
})
 
export default class father extends Vue {
  msg: string = '父组件传过来的msg'
 
  changeChildren() {
    console.log(this.$children) //所有子组件,打印的是一个数组
 
    //找到children组件,改变属性值
    this.$children[0].messageA = 'this is new value from father'
 
    //调用children的方法
    this.$children[0].getName('daming');  //my name is daming
  }
 
}
</script>

Código de subcomponente:

<template>
  <div>
    <p>我是子组件</p>
    <p>{
   
   {messageA}}</p>
    <p>获取父组件的值为:{
   
   {parentVal}}</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
 
@Component({
  name: 'children',
  components: {
     
  }
})
 
export default class father extends Vue {
  messageA: string = 'this is old'
 
  get parentVal(){
    return this.$parent.msg;//拿到父组件传过来的值
  }
 
  getName(name: string) {
    console.log(`my name is ${name}`)
  }
}
</script>

Después de obtener la instancia, el componente principal puede cambiar directamente las propiedades del componente secundario utilizando los métodos del componente secundario. De la misma manera, los componentes secundarios también pueden utilizar directamente las propiedades y métodos de los componentes principales.

Nota: Debe prestar atención a las condiciones de contorno. Por ejemplo, si toma $parent en #app, obtendrá una instancia de new Vue(). Si toma $parent en esta instancia, obtendrá un estado indefinido, y si Si toma $children en el componente secundario inferior, estará vacío.

Pero si el componente principal necesita compartir un atributo compartido, todos sus elementos secundarios deben acceder al atributo compartido. En este caso, el componente secundario puede acceder al recurso compartido a través de this.$parent.share.

Sin embargo, los componentes creados con este patrón siguen siendo propensos a sufrir problemas internos. Por ejemplo, anidamos un subcomponente niños2 dentro del subcomponente, como por ejemplo:

<template>
  <div>
    <p>我是父组件</p>
    <children>
        <children2>
    <children/>
  </div>
</template>
 

Luego, al acceder a compartir en el componente Children2, primero debe verificar si Share existe en su componente principal. Si no existe, búsquelo en un nivel superior e impleméntelo en el código:

var share = this.$parent.share || this.$parent.$parent.share;

Al hacer esto, el componente rápidamente se sale de control: llegar al componente principal hace que la aplicación sea más difícil de depurar y comprender, especialmente cuando se cambian los datos del componente principal. Después de un tiempo, es difícil determinar dónde se inició el cambio.

Entonces $children y $parent son más adecuados para la comunicación de componentes padre-hijo.

Resumen: Los dos métodos anteriores se utilizan para la comunicación entre los componentes padre e hijo, y la recomendación oficial es utilizar accesorios para la comunicación entre los componentes padre e hijo;

 

3. árbitro/árbitros

ref: si se usa en un elemento DOM normal, la referencia apunta al elemento DOM; si se usa en un subcomponente, la referencia apunta a la instancia del componente, a través de la cual se pueden llamar directamente los métodos del componente o acceder a los datos.

Ejemplo:

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    <son ref="mySon" />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  mounted() {
    const mySon: any = this.$refs.mySon;
    console.log(mySon.name) //lingling
    mySon.sayHello(); //hello, I am son
  }
}
</script>

 

Código de subcomponente:

<template>
  <div>
    <p>我是儿子组件</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject } from "vue-property-decorator";
 
@Component({
  name: 'son',
  components: {
     
  }
})
 
export default class son extends Vue {
  name: string = 'lingling'
  sayHello () {
    console.log('hello, I am son')
  }
}
 
</script>

 

4. Vuex

Vuex es un modelo de gestión de estado que utiliza almacenamiento centralizado para gestionar el estado de todos los componentes de la aplicación y utiliza las reglas correspondientes para garantizar que el estado cambie de forma predecible.

El núcleo de la aplicación Vuex es la tienda (almacén, un contenedor), que contiene la mayor parte del estado de su aplicación;

Cada
estado del módulo Vuex: se utiliza para el almacenamiento de datos, es la única fuente de datos en la tienda;
captadores: como las propiedades calculadas en Vue, basadas en el empaquetado secundario de datos de estado, a menudo se usan para el filtrado de datos y el cálculo de correlación de múltiples datos;
Mutaciones : similar a las funciones, la única forma de cambiar datos de estado y no se puede usar para manejar eventos asincrónicos;
acciones: similares a las mutaciones, se usan para enviar mutaciones para cambiar el estado sin cambiar el estado directamente y pueden incluir cualquier operación asincrónica;
módulos : similar En el espacio de nombres, se utiliza en el proyecto para definir y operar el estado de cada módulo por separado para facilitar el mantenimiento;

Vuex implementa un flujo de datos unidireccional y tiene un estado para almacenar datos globalmente. Cuando un componente quiere cambiar los datos en el estado, debe hacerlo a través de Mutation. Mutation también proporciona un modo de suscriptor para que los complementos externos llamen a obtener actualizaciones de los datos del Estado. Cuando todas las operaciones asincrónicas o las operaciones síncronas por lotes requieren acción, la acción no puede modificar directamente el estado y los datos de estado aún deben modificarse mediante mutación. Finalmente, en base a los cambios de estado, se presenta a la vista.

Vuex resuelve el problema de múltiples vistas que dependen del mismo estado y el comportamiento de diferentes vistas que necesitan cambiar el mismo estado, centrando la energía del desarrollador en la actualización de datos en lugar de la transferencia de datos entre componentes.

No les daré un ejemplo de cómo usar vuex, creo que todos lo conocen. Si aún tienes dudas, echa un vistazo a la documentación oficial: https://vuex.vuejs.org/zh/

 

Cinco, proporcionar / inyectar

Concepto: el par de opciones de proporcionar/inyectar deben usarse juntas para permitir que un componente ancestro inyecte una dependencia en todos sus descendientes, sin importar cuán profunda sea la jerarquía del componente, y siempre tendrá efecto cuando las relaciones ascendentes y descendentes sean establecido.

En pocas palabras, las variables se proporcionan mediante provide en el componente principal y luego se inyectan en el componente secundario mediante inject.

 

La opción de proporcionar debe ser: un objeto o una función que devuelva un objeto;

La opción de inyección debe ser: una matriz de cadenas o un objeto, la clave del objeto es el nombre del enlace local;

 

Veamos el siguiente ejemplo:

Ahora hay tres componentes: padre.vue sol.vue nieto.vue donde sun.vue es un subcomponente de padre.vue y nieto.vue es un subcomponente de sun.vue.

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    <son />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  @Provide() text = "I am father"
}
 
</script>

Código del componente hijo:

<template>
  <div>
    <p>我是儿子组件</p>
    <grandson />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject } from "vue-property-decorator";
import grandson from "./grandson.vue"
 
@Component({
  name: 'son',
  components: {
    grandson
  }
})
 
export default class father extends Vue {
  @Inject() readonly text!: string
 
  mounted () {
    console.log(`儿子组件拿到了:${this.text}`) //儿子组件拿到了:I am father
  }
}
 
</script>

Código del componente Sun Tzu:

<template>
  <div>
    <p>我是孙子组件</p>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Inject} from "vue-property-decorator";
 
@Component({
  name: 'grandson',
  components: {
     
  }
})
 
export default class father extends Vue {
  @Inject() readonly text!: string
 
  mounted () {
    console.log(`孙子组件也拿到了:${this.text}`)  //孙子组件也拿到了:I am father
  }
}
 
</script>

El componente principal proporciona atributos de texto, que se pueden obtener en sus componentes hijo y nieto, o directamente en niveles más profundos, sin necesidad de pasar capa por capa.

La API de provisión / inyección resuelve principalmente el problema de comunicación entre componentes de niveles cruzados, pero su escenario de uso es principalmente para que los subcomponentes obtengan el estado de componentes superiores, y se establece una relación entre el suministro activo y la inyección de dependencia entre componentes de niveles cruzados. .

De hecho, puede pensar en la inyección de dependencia como parte de "accesorios ampliamente válidos", excepto:

  • Un componente ancestro no necesita saber qué componentes descendientes utilizan las propiedades que proporciona.
  • Los componentes descendientes no necesitan saber de dónde provienen las propiedades inyectadas.

Sin embargo, la inyección de dependencia todavía tiene efectos negativos. Combina los componentes de su aplicación con la forma en que están organizados actualmente, lo que dificulta la refactorización. Además, las propiedades proporcionadas no responden. Esto es así porque usarlos para crear una escala centralizada de datos no es suficiente. Si la propiedad que desea compartir es específica de su aplicación en lugar de genérica, o si desea actualizar los datos proporcionados en un componente anterior, esto significa que es posible que deba cambiar a uno real como la solución de administración Vuex State.

 

6. autobús de eventos

eventBus también se llama bus de eventos. Se puede utilizar como concepto de puente de comunicación en Vue. Es como si todos los componentes compartieran el mismo centro de eventos. Puede registrarse para enviar eventos o recibir eventos al centro, de modo que los componentes puedan notificar a otros componentes.

Este método utiliza una instancia de Vue vacía como bus de eventos central (centro de eventos), la usa para activar eventos y escuchar eventos, e implementa de manera inteligente y liviana la comunicación entre cualquier componente, incluidos padre-hijo, hermano y entre niveles.

 

Métodos de implementación específicos:

const EventBus=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});

A continuación veamos ejemplos:

Ahora el componente principal tiene dos componentes: niños.vue y niños2.vue. A continuación, veamos cómo estos dos componentes se comunican a través de eventBus.

Primero, necesita crear un bus de eventos y exportarlo para que otros módulos puedan usarlo o escucharlo.

Inicialización: event-bus.js

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    <son />
    <son2 />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
import son2 from "./children2.vue"
 
@Component({
  name: 'father',
  components: {
    son,
    son2
  }
})
 
export default class father extends Vue {
  
}
</script>

 

Código del subcomponente 1:

// 在儿子1组件中发送事件
<template>
  <div>
    <p>我是儿子1组件</p>
    <el-button @click="addNumber">+加法器</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son',
  components: {
  }
})
 
export default class son extends Vue {
  num: number = 1
 
  addNumber() {
    EventBus.$emit('addition', {
      num:this.num++
    })
  }
     
}
</script>

 

Código del subcomponente 2:

//儿子2组件中接收事件
<template>
  <div>
    <p>我是儿子2组件</p>
    <div>计算所得结果: {
   
   {count}}</div>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import {EventBus} from './event-bus.js'
 
@Component({
  name: 'son2',
  components: {
    
  }
})
 
export default class son extends Vue {
    count: number = 0;
 
    mounted() {
      EventBus.$on('addition', (param: any) => {
        this.count = this.count + param.num;
      })
    }
     
 
}
 
</script>

De esta manera, puede hacer clic en el botón sumador en el componente niños.vue y usar el número pasado para mostrar el resultado de la suma en niños2.vue.

eventBus simplifica la comunicación entre componentes, pero también tiene sus desventajas: cuando el proyecto es grande, puede causar fácilmente desastres que son difíciles de mantener.

 

7. $atributos y $oyentes

$attrs: contiene enlaces de atributos (excepto clase y estilo) que no se reconocen (ni se obtienen) como accesorios en el ámbito principal. Cuando un componente no declara ningún accesorio, todos los enlaces de alcance principal (excepto clase y estilo) se incluirán aquí, y los componentes internos se pueden pasar a través de v-bind="$attrs".

$listeners: contiene detectores de eventos v-on en el ámbito principal (sin el modificador .native). Se puede pasar a componentes internos mediante v-on="$listeners".

Ahora analicemos una situación. Ahora el componente padre y el componente nieto están en una relación generacional. ¿Cuáles son las formas en que se comunicaban antes?

  • Utilice el enlace de accesorios para transferir información nivel por nivel.Si el cambio de estado en el componente nieto requiere pasar datos al componente principal, utilice el sistema de eventos para pasarlo nivel por nivel;
  • Usar eventBus es aún más adecuado en este caso, pero cuando varias personas cooperan en el desarrollo, la mantenibilidad del código es baja y la legibilidad también es baja;
  • Utilice vuex para la gestión de datos, pero si solo transfiere datos sin procesamiento intermedio, usar vuex para el procesamiento parece un poco excesivo.

Veamos el siguiente ejemplo:

Código del componente principal:

<template>
  <div>
    <p>我是父组件</p>
    //这里我们可以看到,父组件向儿子组件传递了四个参数和一个方法
    <son
      :name="name"
      :age="age"
      :gender="gender"
      title="我是父组件传过来的title"
      v-on:upText="clickText"
    />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Provide } from "vue-property-decorator";
import son from "./children.vue"
 
@Component({
  name: 'father',
  components: {
    son
  }
})
 
export default class father extends Vue {
  name: string = 'fatherName';
  age: number = 45;
  gender: string = '男'
 
  clickText(val: string) {
    console.log(`当前val是:${val}`); //子组件触发打印:当前val是:I am son    //孙子组件触发打印:当前val是:I am grandson
  }
}
 
</script>

 

Código del componente hijo:

<template>
  <div>
    <p>我是儿子组件</p>
    <p>儿子组件的$attrs: {
   
   { $attrs }}</p>
    <el-button @click="tellFather">点击传值给父组件</el-button>
    <grandson v-bind="$attrs" v-on="$listeners" />
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import grandson from "./grandson.vue"
 
@Component({
  name: 'son',
  components: {
    grandson
  }
})
 
export default class son extends Vue {
  @Prop({
    default: '男'
  })
  gender!: string; //性别作为props属性绑定
 
  created() {
    // 这里的$attrs就是所有从父组件传递过来的所有参数 然后 除去props中显式定义的参数后剩下的所有参数!!!
 
    console.log(this.$attrs,'attrs'); //age:45   name:fatherName  title:我是父组件传过来的title
 
    console.log(this.$listeners,'listeners') //upText:function
  }
 
  tellFather() {
    this.$emit('upText','I am son')
  }
}
 
</script>

 

Código del componente Sun Tzu:

<template>
  <div>
    <p>我是孙子组件</p>
    <p>孙子组件的$attrs: {
   
   { $attrs }}</p>
    <el-button @click="tellGrandFather">点击传值给爷爷组件</el-button>
  </div>
</template>
 
<script lang="ts">
import { Component, Vue, Prop} from "vue-property-decorator";
 
@Component({
  name: 'grandson',
  components: {
     
  }
})
 
export default class grandson extends Vue {
  @Prop({
    default: '12'
  })
  age!: string; //子组件传过来的age作为props被绑定
 
 
  created() {
    // 同理,$attrs这个对象集合中的值 = 所有传值过来的参数 - props中显示定义的参数
    console.log(this.$attrs,'孙子组件的attrs'); //name: fatherName title:我是父组件传过来的title
 
    console.log(this.$listeners,'孙子组件的listeners'); // upText:function
  }
 
  tellGrandFather() {
    this.$emit('upText','I am grandson'); //触发upText事件,直接进行跨级通信
  }
}
 
</script>

 

En general: $attrs y $listeners son dos objetos: $attrs almacena atributos que no son Props vinculados al componente principal y $listeners almacena eventos no nativos vinculados al componente principal. Alguna comunicación entre niveles se puede llevar a cabo fácilmente a través de $attrs y $listeners.

 

Resumen escrito al final:

Según escenarios de uso comunes, se pueden dividir aproximadamente en tres categorías:

  • Comunicación entre los componentes padre e hijo: props; $parent / $children; ref ; provide / inject ; $attrs / $listeners
  • Comunicación entre componentes hermanos: eventBus;vuex;
  • Comunicación cruzada: vuex; eventBus; proporcionar / inyectar; $attrs / $listeners

 

Hay muchas formas de comunicarse entre componentes y elegir diferentes métodos de comunicación en escenarios apropiados también brindará una gran comodidad al desarrollo.

Supongo que te gusta

Origin blog.csdn.net/weixin_46422035/article/details/114540124
Recomendado
Clasificación