Comunicación del componente padre-hijo de Vue (diez tipos)

Entrevistador: ¿Cuáles son las formas de comunicarse entre los componentes padre e hijo en Vue?

Piénsalo por un minuto.

Es innegable que tanto las grandes como las pequeñas fábricas ya han utilizado el framework Vue.js. Es simple y fácil de usar, sin mencionar que el tutorial es detallado, la comunidad está activa y hay muchos kits de terceros. Realmente es una habilidad esencial para los desarrolladores front-end. Y en la entrevista, a menudo se hacen varias preguntas sobre Vue, y la mayoría de los entrevistadores harán las preguntas anteriores.

Recientemente, he estado haciendo optimizaciones a nivel de código de proyectos de Vue. Para ser honesto, optimizar los códigos de otras personas es realmente algo doloroso. Si no habla sobre la implementación de la función, puedo escribir otro artículo sobre la especificación del código. Realmente no hay estándar ni radio. ¡Es demasiado importante regular esto! Es un poco una broma, volviendo al tema, tos, tos, hablemos sobre mi comprensión de las preguntas de la entrevista anteriores, la redacción es limitada y algo anda mal. Bienvenido a dejar un comentario al final del artículo.

Visión de conjunto

Varios métodos de comunicación no son más que los siguientes:

  • Prop(Comúnmente utilizado)

  • $emit (Más utilizado para embalaje de componentes)

  • .syncAzúcar sintáctico (menos)

  • $attrs Y  $listeners (más utilizado para embalaje de componentes)

  • provide Y  inject (los componentes / bibliotecas de componentes de gama alta se utilizan más)

  • Otra comunicación

Detalle

Vamos a presentarlos uno por uno, por favor, recorra.

1. Prop
pronunciación británica: [prɒp]. Esto se usa mucho en nuestro desarrollo diario. En términos simples, podemos pasar datos a componentes secundarios a través de la Prop. Para usar una metáfora vívida, la transferencia de datos entre los componentes principal y secundario es equivalente a una tubería de alcantarillado de arriba hacia abajo, que solo puede fluir de arriba hacia abajo, no corriente arriba. Este es exactamente el flujo de datos unidireccional de la filosofía de diseño de Vue. Prop es solo una interfaz entre la tubería y la tubería, para que el agua (datos) pueda fluir hacia abajo. Habiendo dicho eso, mira el código:

<div id="app">
 
  <child :content="message"></child>
 
</div>
 
// Js
 
let Child = Vue.extend({
    
    
 
  template: '<h2>{
    
    { content }}</h2>',
 
  props: {
    
    
 
    content: {
    
    
 
      type: String,
 
      default: () => {
    
     return 'from child' }
 
    }
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  data: {
    
    
 
    message: 'from parent'
 
  },
 
  components: {
    
    
 
    Child
 
  }
 
})

Salida del navegador:

from parent

 
  
  

2. La
pronunciación británica de $ emit: [iˈmɪt]. La declaración oficial es activar un evento en la instancia actual. Se pasarán parámetros adicionales a la devolución de llamada del oyente . Según tengo entendido, no sé si puedo explicártelo. Echemos un vistazo breve al código:

<div id="app">
 
  <my-button @greet="sayHi"></my-button>
 
</div>
 
let MyButton = Vue.extend({
    
    
 
  template: '<button @click="triggerClick">click</button>',
 
  data () {
    
    
 
    return {
    
    
 
      greeting: 'vue.js!'
 
    }
 
  },
 
  methods: {
    
    
 
    triggerClick () {
    
    
 
      this.$emit('greet', this.greeting)
 
    }
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  components: {
    
    
 
    MyButton
 
  },
 
  methods: {
    
    
 
    sayHi (val) {
    
    
 
      alert('Hi, ' + val) // 'Hi, vue.js!'
 
    }
 
  }
 
})

La lógica general es la de Jianger: cuando hago clic en el botón de la página, activo el MyButtonevento de escucha en el componente greety paso los parámetros a la función de devolución de llamada sayHi. Para decirlo sin rodeos, antes de emitir (distribuir) un evento desde el componente hijo, internamente tiene activado (escuchado) el evento y su devolución de llamada de escucha en la cola de eventos por adelantado. De hecho, es equivalente a la siguiente escritura:

vm.$on('greet', function sayHi (val) {
    
    
 
  console.log('Hi, ' + val)
 
})
 
vm.$emit('greet', 'vue.js')
 
// => "Hi, vue.js"

3. Modificador .sync
Este tipo solía ser una función de enlace bidireccional en [email protected], es decir, el componente hijo puede modificar el valor en el componente padre. Debido a que violó el concepto de diseño de flujo de datos unidireccional, fue eliminado en [email protected]. Pero en [email protected]+ y versiones superiores, este modificador .sync ha sido reintroducido. Pero esta vez solo existe como azúcar sintáctico en tiempo de compilación. Se expandirá a un oyente v-on que actualiza automáticamente las propiedades del componente principal. Para decirlo sin rodeos, actualice manualmente el valor en el componente principal para que la fuente del cambio de datos sea más obvia. Aquí hay un párrafo de la introducción oficial:

En algunos casos, es posible que necesitemos "enlazar en dos direcciones" un accesorio. Desafortunadamente, el enlace bidireccional verdadero traerá problemas de mantenimiento, porque el componente hijo puede modificar el componente padre y no hay una fuente obvia de cambio en el componente padre y el componente hijo.

Dado que es un azúcar sintáctico, debe ser una forma abreviada de una determinada forma de escribir. ¿Qué forma de escribir? Mira el código:

Entonces podemos usar .syncazúcar sintáctico para abreviar de la siguiente manera:

<text-document
 
  v-bind:title="doc.title"
 
  v-on:update:title="doc.title = $event">
 
</text-document>
<text-document v-bind:title.sync="doc.title"></text-document>

Tantas tonterías, ¿cómo lograr una "unión bidireccional"? ¡Entremos en el anuncio, será más emocionante después del anuncio! ... Está bien, bienvenido de nuevo. Supongamos que queremos lograr tal efecto: cambiar el valor en el cuadro de texto del componente secundario también cambia el valor en el componente principal. ¿Cómo hacerlo? Piense en ello primero. Mira el código primero:

<div id="app">
 
  <login :name.sync="userName"></login> {
    
    {
    
     userName }}
 
</div>
 
let Login = Vue.extend({
    
    
 
  template: `
 
    <div class="input-group">
 
      <label>姓名:</label>
 
      <input v-model="text">
 
    </div>
 
  `,
 
  props: ['name'],
 
  data () {
    
    
 
    return {
    
    
 
      text: ''
 
    }
 
  },
 
  watch: {
    
    
 
    text (newVal) {
    
    
 
      this.$emit('update:name', newVal)
 
    }
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  data: {
    
    
 
    userName: ''
 
  },
 
  components: {
    
    
 
    Login
 
  }
 
})

A continuación se muestra el punto clave, hay esta oración en el código:

this.$emit('update:name', newVal)

 
  
  

La sintaxis oficial es: update:myPropNameque myPropNamerepresenta el valor de la propiedad a actualizar. Por supuesto, si usa el. $ Emit anterior sin el azúcar .sync, se puede lograr el mismo efecto. ¡Eso es!

4. $attrsy$listeners

  • $attrsLa explicación en el sitio web oficial es la siguiente:

Contiene enlaces de características ( classy styleexcepciones) que no se reconocen (y adquieren) como accesorios en el ámbito principal . Cuando un componente no declara ningún prop, contendrá todos los enlaces de alcance principal ( classy styleexcepciones) y puede v-bind="$attrs"pasar componentes internos, muy útil cuando se crean componentes de alto nivel.

  • $listenersLa explicación en el sitio web oficial es la siguiente:

Contiene detectores de eventos en el ámbito principal (sin .nativedecoradores) v-on. Se puede v-on="$listeners"pasar en componentes internos, muy útil al crear componentes de nivel superior.

Creo que los atributos $attrsy $listenersson como dos cajas de almacenamiento, una es responsable de almacenar atributos y la otra es responsable de almacenar eventos, los cuales almacenan datos en forma de objetos. Consulte la siguiente explicación del código:

<div id="app">
 
  <child
 
    :foo="foo"
 
    :bar="bar"
 
    @one.native="triggerOne"
 
    @two="triggerTwo">
 
  </child>
 
</div>

Como puede ver en HTML, hay dos atributos y dos métodos, la diferencia es que el atributo es una propdeclaración y el evento es un .nativemodificador.

let Child = Vue.extend({
    
    
 
  template: '<h2>{
    
    { foo }}</h2>',
 
  props: ['foo'],
 
  created () {
    
    
 
    console.log(this.$attrs, this.$listeners)
 
    // -> {
    
    bar: "parent bar"}
 
    // -> {
    
    two: fn}
 
 
 
    // 这里我们访问父组件中的 `triggerTwo` 方法
 
    this.$listeners.two()
 
    // -> 'two'
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  data: {
    
    
 
    foo: 'parent foo',
 
    bar: 'parent bar'
 
  },
 
  components: {
    
    
 
    Child
 
  },
 
  methods: {
    
    
 
    triggerOne () {
    
    
 
      alert('one')
 
    },
 
    triggerTwo () {
    
    
 
      alert('two')
 
    }
 
  }
 
})
可以看到,我们可以通过$attrs$listeners进行数据传递,在需要的地方进行调用和处理,还是很方便的。当然,我们还可以通过v-on="$listeners"一级级的往下传递,子子孙孙无穷尽也!

一个插曲!

当我们在组件上赋予了一个非Prop 声明时,编译之后的代码会把这些个属性都当成原始属性对待,添加到 html 原生标签上,看上面的代码编译之后的样子:

<h2 bar="parent bar">parent foo</h2>
这样会很难看,同时也爆了某些东西。如何去掉?这正是 inheritAttrs 属性的用武之地!给组件加上这个属性就行了,一般是配合$attrs使用。看代码:

// 源码
 
let Child = Vue.extend({
    
    
 
  ...
 
  inheritAttrs: false, // 默认是 true
 
  ...
 
})

Como puede ver, es muy conveniente para nosotros pasar $attrsy $listenerstransferir datos, llamar y procesar donde sea necesario. Por supuesto, también podemos pasar por el v-on="$listeners"primer nivel, ¡descendientes infinitos!

¡Un episodio!

Cuando asignamos una declaración que no es Prop en el componente, el código compilado tratará estos atributos como atributos originales y los agregará a las etiquetas nativas html. Vea cómo se ve el código anterior después de ser compilado:

<h2 bar="parent bar">parent foo</h2>

 
  
  

Esto será feo y explotará algo. ¿Cómo eliminarlo? ¡Aquí es donde entra el atributo heritageAttrs! Simplemente agregue este atributo al componente, generalmente se usa en conjunto $attrs. Mira el código:


 
  
  
  1. // Código fuente
  2. let Child = Vue.extend ({
  3. ...
  4. heritageAttrs: false , // El valor predeterminado es verdadero
  5. ...
  6. })

Compila de nuevo:

<h2>parent foo</h2>

 
  
  

5. provide/inject
Son muy misteriosos para CP. Eche un vistazo a la descripción oficial de proporcionar / inyectar:

provideY injectproporciona principalmente casos de uso para bibliotecas de componentes / complementos de gama alta. No se recomienda para uso directo en el código de la aplicación. Y este par de opciones deben usarse juntas para permitir que un componente ancestro inyecte una dependencia a todos sus descendientes, sin importar cuán profundo sea el nivel del componente, y siempre tendrá efecto cuando se establezca la relación ascendente y descendente.

¡Un poco ignorante después de leer la descripción! Un resumen de una oración es: cuando eras joven, tu papá te lo guardaba todo. Cuando crezcas, deberías casarte con una esposa. Quieres una casa o un automóvil para ti, siempre que él tenga todo lo que pueda. Aquí está la explicación del código de esta oración:

<div id="app">
 
  <son></son>
 
</div>
 
let Son = Vue.extend({
    
    
 
  template: '<h2>son</h2>',
 
  inject: {
    
    
 
    house: {
    
    
 
      default: '没房'
 
    },
 
    car: {
    
    
 
      default: '没车'
 
    },
 
    money: {
    
    
 
      // 长大工作了虽然有点钱
 
      // 仅供生活费,需要向父母要
 
      default: '¥4500'
 
    }
 
  },
 
  created () {
    
    
 
    console.log(this.house, this.car, this.money)
 
    // -> '房子', '车子', '¥10000'
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  provide: {
    
    
 
    house: '房子',
 
    car: '车子',
 
    money: '¥10000'
 
  },
 
  components: {
    
    
 
    Son
 
  }
 
})

6. Otros métodos de comunicación
Además de los cinco métodos anteriores, existen en realidad:

  • EventBus

La idea es declarar una variable de instancia global de Vue EventBusy almacenar todos los datos de comunicación y monitoreo de eventos en esta variable. De esta manera, se logra el intercambio de datos entre componentes, similar a Vuex. Pero este método solo es adecuado para proyectos muy pequeños, y Vuex se recomienda para proyectos complejos. Aquí está el código simple para implementar EventBus:

<div id="app">
 
  <child></child>
 
</div>
 
// 全局变量
 
let EventBus = new Vue()
 
 
 
// 子组件
 
let Child = Vue.extend({
    
    
 
  template: '<h2>child</h2>',
 
  created () {
    
    
 
    console.log(EventBus.message)
 
    // -> 'hello'
 
    EventBus.$emit('received', 'from child')
 
  }
 
})
 
 
 
new Vue({
    
    
 
  el: '#app',
 
  components: {
    
    
 
    Child
 
  },
 
  created () {
    
    
 
    // 变量保存
 
    EventBus.message = 'hello'
 
    // 事件监听
 
    EventBus.$on('received', function (val) {
    
    
 
      console.log('received: '+ val)
 
      // -> 'received: from child'
 
    })
 
  }
 
})
  • Vuex

Recomendado oficialmente, Vuex es un modo de administración de estado desarrollado específicamente para aplicaciones Vue.js.

  • $ padre

La instancia principal, si la instancia actual tiene una. La interacción entre los datos también se puede llevar a cabo accediendo a la instancia principal, pero en casos excepcionales, los datos del componente principal se modificarán directamente.

  • $ raíz

La instancia raíz de Vue del árbol de componentes actual. Si la instancia actual no tiene una instancia principal, esta instancia será ella misma. La interacción entre los datos también se puede llevar a cabo accediendo al componente raíz, pero en casos muy raros los datos del componente padre se modificarán directamente.

  • difusión / envío

Son métodos en [email protected], que son la transmisión y el envío de eventos. Aunque se ha eliminado [email protected], estos dos métodos se pueden simular. Puede aprender de Element para lograrlo. A veces es muy útil, como cuando estamos desarrollando componentes de árbol.

para resumir

Después de tanto prolijo, espero ver a los estudiantes ganar más o menos. Por favor, deje un comentario si algo anda mal, estoy muy agradecido. En realidad, existen muchos tipos de comunicación entre los componentes principal y secundario, según las circunstancias que utilice. Los diferentes escenarios se tratan de manera diferente. ¡La premisa es que tienes que saberlo! Aún queda un largo camino por recorrer a través del Gran Dios. Mientras mires la comunidad todos los días, mires la documentación, escribas demostraciones y progreses un poco todos los días, siempre ganarás.

 

Entrevistador: ¿Cuáles son las formas de comunicarse entre los componentes padre e hijo en Vue?

Supongo que te gusta

Origin blog.csdn.net/weixin_46034375/article/details/108541546
Recomendado
Clasificación