Pasando datos a componentes en vue.js

92

Estoy luchando por entender cómo pasar datos entre componentes en vue.js. Leí los documentos varias veces y miré muchas preguntas y tutoriales relacionados con vue, pero todavía no lo entiendo.

Para entender esto, espero recibir ayuda para completar un ejemplo bastante simple

  1. mostrar una lista de usuarios en un componente (hecho)
  2. enviar los datos del usuario a un nuevo componente cuando se hace clic en un enlace (hecho); consulte la actualización en la parte inferior.
  3. editar los datos del usuario y enviarlos de vuelta al componente original (no he llegado tan lejos)

Aquí hay un violín, que falla en el paso dos: https://jsfiddle.net/retrogradeMT/d1a8hps0/

Entiendo que necesito usar accesorios para pasar datos al nuevo componente, pero no estoy seguro de cómo hacerlo funcionalmente. ¿Cómo vinculo los datos al nuevo componente?

HTML:

    <div id="page-content">
       <router-view></router-view>
     </div>

 <template id="userBlock" >
   <ul>
     <li v-for="user in users">{{user.name}} - <a v-link="{ path: '/new' }"> Show new component</a>
     </li>
   </ul>
 </template>

  <template id="newtemp" :name ="{{user.name}}">
    <form>
      <label>Name: </label><input v-model="name">
      <input type="submit" value="Submit">
    </form>
  </template>

js para el componente principal:

Vue.component('app-page', {
  template: '#userBlock',

  data: function() {
    return{

        users: []
      }
    },

ready: function () {
    this.fetchUsers();
},

methods: {
    fetchUsers: function(){
        var users = [
          {
            id: 1,
            name: 'tom'
          },
          {
            id: 2,
            name: 'brian'
          },
          {
            id: 3,
            name: 'sam'
          },
        ];

        this.$set('users', users);
     }
    }
  })

JS para el segundo componente:

Vue.component('newtemp', {
  template: '#newtemp',
  props: 'name',
  data: function() {
    return {
        name: name,
        }
   },
})

ACTUALIZAR

Ok, ya he resuelto el segundo paso. Aquí hay un nuevo violín que muestra el progreso: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Como estoy usando el enrutador Vue, no uso accesorios para enviar los datos a un nuevo componente. En su lugar, necesito establecer parámetros en el v-link y luego usar un gancho de transición para aceptarlo.

Los cambios de V-link ven las rutas con nombre en los documentos de vue-router :

<a v-link="{ name: 'new', params: { name: user.name }}"> Show new component</a>

Luego, en el componente, agregue datos a las opciones de ruta, vea los ganchos de transición :

Vue.component('newtemp', {
  template: '#newtemp',
  route: {
   data: function(transition) {
        transition.next({
            // saving the id which is passed in url
            name: transition.to.params.name
        });
     }
  },
 data: function() {
    return {
        name:name,
        }
   },
})
retrógrado
fuente

Respuestas:

46

------------- Lo siguiente es aplicable solo a Vue 1 --------------

La transferencia de datos se puede realizar de varias formas. El método depende del tipo de uso.


Si desea pasar datos de su html mientras agrega un nuevo componente. Eso se hace usando accesorios.

<my-component prop-name="value"></my-component>

Este valor de prop estará disponible para su componente solo si agrega el nombre de prop prop-namea su propsatributo.


Cuando se pasan datos de un componente a otro componente debido a algún evento dinámico o estático. Eso se hace mediante el uso de emisores y distribuidores de eventos. Entonces, por ejemplo, si tiene una estructura de componentes como esta:

<my-parent>
    <my-child-A></my-child-A>
    <my-child-B></my-child-B>
</my-parent>

Y que desea enviar datos a partir <my-child-A>de <my-child-B>entonces en <my-child-A>que tendrá que enviar un evento:

this.$dispatch('event_name', data);

Este evento recorrerá toda la cadena principal. Y desde cualquier padre que tenga una rama hacia <my-child-B>usted, transmita el evento junto con los datos. Entonces en el padre:

events:{
    'event_name' : function(data){
        this.$broadcast('event_name', data);
    },

Ahora, esta transmisión viajará por la cadena secundaria. Y a cualquier niño que desee agarrar el evento, en nuestro caso <my-child-B>agregaremos otro evento:

events: {
    'event_name' : function(data){
        // Your code. 
    },
},

La tercera forma de pasar datos es a través de parámetros en v-links. Este método se utiliza cuando las cadenas de componentes están completamente destruidas o en los casos en que cambia el URI. Y puedo ver que ya los entiendes.


Decida qué tipo de comunicación de datos desea y elija de forma adecuada.

notANerdDev
fuente
1
Gracias, eso fue realmente útil. La única pieza con la que todavía estoy luchando son las convenciones de nombres. es decir: tengo user.name que paso a través de v-link como nombre. Ahora puedo editar la variable de nombre y devolverla al componente original como nombre, pero el componente original no tiene un nombre llamado var. ¿Que me estoy perdiendo aqui? ¿No parece posible pasar un objeto a través de v-link?
retrógrado
1
Ya estás pasando un objeto. paramses un objeto. La clave de nombre se puede asignar a this.user.namesu componente. Crea un violín si necesitas ayuda y házmelo saber. Mira esto: vuejs.github.io/vue-router/en/route.html
notANerdDev
Ah, está bien, lo tengo ahora. Gracias de nuevo. Agradezco tu ayuda, realmente dejó las cosas mucho más claras.
retrógrado
6
Respuesta impresionante, pero según tengo entendido, no funcionará con 2.0 ya que los eventos han quedado obsoletos.
rix
2
Me encantó la respuesta, pero luego llegué a los comentarios y, como estoy trabajando con Vue 2, siento que no voy a poder usar el segundo método sugerido por ti. ¿Es eso correctamente temido?
Konrad Viltersten
23

La mejor forma de enviar datos desde un componente principal a un hijo es utilizando accesorios .

Pasar datos de padres a hijos a través de props

  • Declarar props(matriz u objeto ) en el niño
  • Páselo al niño a través de <child :name="variableOnParent">

Vea la demostración a continuación:

Vue.component('child-comp', {
  props: ['message'], // declare the props
  template: '<p>At child-comp, using props in the template: {{ message }}</p>',
  mounted: function () {
    console.log('The props are also available in JS:', this.message);
  }
})

new Vue({
  el: '#app',
  data: {
    variableAtParent: 'DATA FROM PARENT!'
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app">
  <p>At Parent: {{ variableAtParent }}<br>And is reactive (edit it) <input v-model="variableAtParent"></p>
  <child-comp :message="variableAtParent"></child-comp>
</div>

acdcjunior
fuente
pequeña corrección: "<child-comp" en lugar de "<child" y variableAtParent .. Páselo al niño a través de <child-comp: name = "variableAtParent">
muenalan
Solo funcionará con propiedad simple, las referencias a objetos no se actualizarán. Por ejemplo, si la propiedad principal es una matriz y esta matriz se reemplazó en el objeto principal por otra matriz, el niño no la verá.
Stan Sokolov
@StanSokolov para nada. Sí trabajo para matrices, consulte: jsfiddle.net/acdcjunior/q4mank05 . Si su matriz no es reactiva, probablemente se esté enfrentando a un problema de reactividad. Intente usar Vue.set, más aquí: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior
¿Qué sentido tiene si no es reactivo? Seguro que fue reactivo con referencia constantemente reemplazada por una nueva matriz. Vue no propaga "cambios de referencia" a los niños, solo cambios de valor en elementos simples. Entonces, si la referencia a la matriz se sobrescribió en parent, los niños seguirán viendo la referencia anterior. Nunca sabré que el padre ahora trabaja con un objeto diferente.
Stan Sokolov
@StanSokolov Vea esto: jsfiddle.net/acdcjunior/ftmrne2h la matriz se reemplaza en parent y el niño ve / reacciona a ella (haga clic en el botón para probar). ¿O te refieres a otra cosa? Si es así, sería útil editar el violín para mostrarlo
acdcjunior
15

Creo que el problema está aquí:

<template id="newtemp" :name ="{{user.name}}">

Cuando le pone el prefijo al prop, :le indica a Vue que es una variable, no una cadena. Entonces no necesitas el {{}}alrededor user.name. Tratar:

<template id="newtemp" :name ="user.name">

EDITAR-----

Lo anterior es cierto, pero el problema más grande aquí es que cuando cambia la URL y va a una nueva ruta, el componente original desaparece. Para que el segundo componente edite los datos principales, el segundo componente debería ser un componente secundario del primero, o simplemente una parte del mismo componente.

Jeff
fuente
Gracias jeff. Intenté eliminar el {{}} pero sigo recibiendo los mismos errores.
retrógrado
2

Encontré una manera de pasar los datos de los padres al alcance del componente en Vue, creo que es un poco complicado, pero tal vez esto te ayude.

1) Datos de referencia en Vue Instance como un objeto externo (data : dataObj)

2) Luego, en la función de retorno de datos en el componente secundario, simplemente regrese parentScope = dataObjy listo. Ahora no puedes hacer cosas así {{ parentScope.prop }}y funcionarás de maravilla .

¡Buena suerte!

Lucas Serena
fuente
Eso es unir ambos componentes, lo que puede estar bien para un árbol y sus nodos, pero que normalmente no se favorece. Trataría de evitar esto.
diciembre
1

Las respuestas mencionadas anteriormente funcionan bien, pero si desea pasar datos entre 2 componentes hermanos, también se puede utilizar el bus de eventos. Consulte este blog que lo ayudará a comprender mejor.

supongamos que para 2 componentes: CompA y CompB tienen el mismo padre y main.js para configurar la aplicación principal de vue. Para pasar datos de CompA a CompB sin involucrar el componente principal, puede hacer lo siguiente.

en el archivo main.js, declare una instancia de Vue global separada, que será el bus de eventos.

export const bus = new Vue();

En CompA, donde se genera el evento: hay que emitir el evento al bus.

methods: {
      somethingHappened (){
          bus.$emit('changedSomething', 'new data');
      }
  }

Ahora la tarea es escuchar el evento emitido, entonces, en CompB, puedes escuchar like.

created (){
    bus.$on('changedSomething', (newData) => {
      console.log(newData);
    })
  }

Ventajas:

  • Código Less & Clean.
  • Los padres no deben participar en la transmisión de datos de una composición secundaria a otra (a medida que aumenta el número de hijos, será difícil de mantener)
  • Sigue el enfoque de pub-sub.
Divesh Sahu
fuente
0

Accedo a las propiedades principales usando $root.

Vue.component("example", { 
    template: `<div>$root.message</div>`
});
...
<example></example>
T.Todua
fuente
-2

Se puede usar una variable JS global (objeto) para pasar datos entre componentes. Ejemplo: pasar datos de Ammlogin.vue a Options.vue. En Ammlogin.vue, rspData se establece en la respuesta del servidor. En Options.vue, la respuesta del servidor está disponible a través de rspData.

index.html:

<script>
    var rspData; // global - transfer data between components
</script>

Ammlogin.vue:

....    
export default {
data: function() {return vueData}, 
methods: {
    login: function(event){
        event.preventDefault(); // otherwise the page is submitted...
        vueData.errortxt = "";
        axios.post('http://vueamm...../actions.php', { action: this.$data.action, user: this.$data.user, password: this.$data.password})
            .then(function (response) {
                vueData.user = '';
                vueData.password = '';
                // activate v-link via JS click...
                // JSON.parse is not needed because it is already an object
                if (response.data.result === "ok") {
                    rspData = response.data; // set global rspData
                    document.getElementById("loginid").click();
                } else {
                    vueData.errortxt = "Felaktig avändare eller lösenord!"
                }
            })
            .catch(function (error) {
                // Wu oh! Something went wrong
                vueData.errortxt = error.message;
            });
    },
....

Options.vue:

<template>
<main-layout>
  <p>Alternativ</p>
  <p>Resultat: {{rspData.result}}</p>
  <p>Meddelande: {{rspData.data}}</p>
  <v-link href='/'>Logga ut</v-link>
</main-layout>
</template>
<script>
 import MainLayout from '../layouts/Main.vue'
 import VLink from '../components/VLink.vue'
 var optData = { rspData: rspData}; // rspData is global
 export default {
   data: function() {return optData},
   components: {
     MainLayout,
     VLink
   }
 }
</script>
Kjelle J
fuente