javascript - vuejs - vue js custom event
vuejs actualiza datos primarios del componente secundario (7)
Estoy empezando a jugar con vuejs (2.0).
Construí una página simple con un componente en ella.
La página tiene una instancia de Vue con datos.
En esa página me registré y agregué el componente a html.
El componente tiene una
input[type=text]
.
Quiero que ese valor se refleje en el padre (instancia principal de Vue).
¿Cómo actualizo correctamente los datos primarios del componente? Pasar un accesorio encuadernado del padre no es bueno y arroja algunas advertencias a la consola. Tienen algo en su documento pero no funciona.
De la documentation :
En Vue.js, la relación del componente padre-hijo se puede resumir como accesorios, eventos arriba. El padre pasa los datos al niño a través de accesorios, y el niño envía mensajes al padre a través de eventos. Veamos cómo funcionan a continuación.
Cómo pasar accesorios
El siguiente es el código para pasar accesorios a un elemento hijo:
<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
Cómo emitir evento
HTML:
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
JS:
Vue.component(''button-counter'', {
template: ''<button v-on:click="increment">{{ counter }}</button>'',
data: function () {
return {
counter: 0
}
},
methods: {
increment: function () {
this.counter += 1
this.$emit(''increment'')
}
},
})
new Vue({
el: ''#counter-event-example'',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
El enlace bidireccional ha quedado en desuso en Vue 2.0 a favor del uso de una arquitectura más controlada por eventos.
En general, un niño no debe mutar sus accesorios.
Más bien, debería
$emit
eventos y dejar que el padre responda a esos eventos.
En su caso específico, puede usar un componente personalizado con
v-model
.
Esta es una sintaxis especial que permite algo cercano al enlace bidireccional, pero en realidad es una abreviatura de la arquitectura basada en eventos descrita anteriormente.
Puede leer sobre esto aquí ->
https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events
.
Aquí hay un ejemplo simple:
Vue.component(''child'', {
template: ''#child'',
//The child has a prop named ''value''. v-model will automatically bind to this prop
props: [''value''],
methods: {
updateValue: function (value) {
this.$emit(''input'', value);
}
}
});
new Vue({
el: ''#app'',
data: {
parentValue: ''hello''
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>Parent value: {{parentValue}}</p>
<child v-model="parentValue"></child>
</div>
<template id="child">
<input type="text" v-bind:value="value" v-on:input="updateValue($event.target.value)">
</template>
Los documentos afirman que
<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>
es equivalente a
<custom-input v-model="something"></custom-input>
Es por eso que el accesorio en el niño necesita ser nombrado valor, y por qué el niño necesita $ emitir un evento llamado
input
.
En componente hijo:
<component @eventname="updateparent"></component>
methods: {
updateparent(variable) {
this.parentvariable = variable
}
}
En el componente principal:
this.$emit(''update:title'', newTitle)
Estoy de acuerdo con la emisión de eventos y las respuestas del modelo v para los anteriores. Sin embargo, pensé en publicar lo que encontré sobre componentes con múltiples elementos de formulario que desean emitir a sus padres, ya que este parece ser uno de los primeros artículos devueltos por Google.
Sé que la pregunta especifica una sola entrada, pero esta parecía la coincidencia más cercana y podría ahorrarle a la gente algo de tiempo con componentes vue similares.
Además, nadie ha mencionado aún el modificador
.sync
.
Hasta donde sé, la solución
v-model
solo es adecuada para una entrada que regresa a su padre.
Me tomé un poco de tiempo buscándolo, pero la documentación de Vue (2.3.0) muestra cómo sincronizar múltiples accesorios enviados en el componente de regreso al padre (a través de la emisión, por supuesto).
Se llama apropiadamente el modificador
.sync
.
Esto es lo documentation dice la documentation :
En algunos casos, es posible que necesitemos un "enlace bidireccional" para un accesorio. Desafortunadamente, el enlace bidireccional verdadero puede crear problemas de mantenimiento, porque los componentes secundarios pueden mutar al padre sin que la fuente de esa mutación sea obvia tanto en el padre como en el niño.
Por eso, en su lugar, recomendamos emitir eventos en el patrón de
update:myPropName
. Por ejemplo, en un componente hipotético con untitle
propiedad, podríamos comunicar la intención de asignar un nuevo valor con:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
Luego, el padre puede escuchar ese evento y actualizar una propiedad de datos local, si así lo desea. Por ejemplo:
<text-document v-bind:title.sync="doc.title"></text-document>
Para mayor comodidad, ofrecemos una abreviatura de este patrón con el modificador .sync:
Vue.component(''child'', {
template: ''#child'',
props: {post: Object},
methods: {
updateValue: function () {
this.$emit(''changed'');
}
}
});
new Vue({
el: ''#app'',
data: {
post: {msg: ''hello''},
changed: false
},
methods: {
saveChanges() {
this.changed = true;
}
}
});
También puede sincronizar múltiples a la vez enviando a través de un objeto. Mira la documentation
La forma más simple es usar
this.$emit
Padre vue
<template>
<div>
<button @click="replyDaddy">Reply Daddy</button>
</div>
</template>
<script>
export default {
name: "Child",
methods: {
replyDaddy() {
this.$emit("listenerChild", "I''m here my Daddy!");
}
}
};
</script>
Child.vue
<template> <div> <button @click="replyDaddy">Reply Daddy</button> </div> </template> <script> export default { name: "Child", methods: { replyDaddy() { this.$emit("listenerChild", "I''m here my Daddy!"); } } }; </script>
Mi ejemplo completo: https://codesandbox.io/s/update-parent-property-ufj4b
También es posible pasar accesorios como Object o Array. En este caso, los datos se vincularán en dos sentidos:
(Esto se observa al final del tema: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow )
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>Parent value: {{post.msg}}</p>
<p v-if="changed == true">Parent msg: Data been changed - received signal from child!</p>
<child :post="post" v-on:changed="saveChanges"></child>
</div>
<template id="child">
<input type="text" v-model="post.msg" v-on:input="updateValue()">
</template>
<template>
<div>
<h1>{{ message }}</h1>
<child v-on:listenerChild="listenerChild"/>
</div>
</template>
<script>
import Child from "./Child";
export default {
name: "Father",
data() {
return {
message: "Where are you, my Child?"
};
},
components: {
Child
},
methods: {
listenerChild(reply) {
this.message = reply;
}
}
};
</script>