vuejs memperbarui data induk dari komponen anak


155

Saya mulai bermain dengan vuejs (2.0). Saya membangun halaman sederhana dengan satu komponen di dalamnya. Halaman memiliki satu instance Vue dengan data. Pada halaman itu saya mendaftar dan menambahkan komponen ke html. Komponen memiliki satu input[type=text]. Saya ingin nilai itu mencerminkan orangtua (contoh Vue utama).

Bagaimana cara saya memperbarui data induk komponen dengan benar? Melewati prop terikat dari orang tua tidak baik dan melemparkan beberapa peringatan ke konsol. Mereka memiliki sesuatu dalam dokumen mereka tetapi tidak berfungsi.


1
Bisakah Anda menambahkan kode yang Anda coba, yang tidak berfungsi.
Saurabh

Jawaban:


181

Pengikatan dua arah telah ditinggalkan dalam Vue 2.0 demi penggunaan arsitektur yang lebih digerakkan oleh peristiwa. Secara umum, seorang anak tidak boleh mengubah alat peraga. Sebaliknya, itu harus $emitacara dan biarkan orang tua menanggapi peristiwa itu.

Dalam kasus spesifik Anda, Anda dapat menggunakan komponen khusus dengan v-model. Ini adalah sintaks khusus yang memungkinkan untuk sesuatu yang dekat dengan pengikatan dua arah, tetapi sebenarnya adalah singkatan untuk arsitektur berbasis peristiwa yang dijelaskan di atas. Anda dapat membacanya di sini -> https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events .

Berikut ini contoh sederhana:

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>


Dokumen menyatakan itu

<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>

setara dengan

<custom-input v-model="something"></custom-input>

Karena itulah properti pada anak perlu dinamai nilai, dan mengapa anak perlu $ memancarkan suatu peristiwa bernama input.


terima kasih pertama atas jawabannya. dapatkah Anda memperluas, atau menunjuk lebih baik ke dokumen tentang acara 'masukan'? sepertinya acara built in.
Gal Ziv

Saya telah menambahkan klarifikasi, dan membuat tautan ke dokumentasi lebih jelas.
asemahle

1
Saya menghilangkan prop "nilai" untuk komponen dan fungsi yang dibuat dan masih berfungsi. dapatkah Anda menjelaskan mengapa Anda menggunakannya?
xetra11

1
Jika Anda tidak menambahkan prop, maka itu akan undefinedsampai perubahan pertama. Lihat biola ini tempat saya berkomentar props: ['value']. Perhatikan bagaimana nilai awal undefined, alih-alih hello: jsfiddle.net/asemahle/8Lrkfxj6 . Setelah perubahan pertama, Vue secara dinamis menambahkan prop nilai ke komponen, sehingga berfungsi.
asemahle

Saya membaca ini di dokumen. Contoh kerja yang bagus. +10 jika aku bisa!
clay

121

Dari dokumentasi :

Dalam Vue.js, hubungan komponen orang tua dan anak dapat diringkas sebagai props down, peristiwa naik. Orang tua meneruskan data ke anak melalui alat peraga, dan anak mengirim pesan ke orang tua melalui acara. Mari kita lihat bagaimana mereka bekerja selanjutnya.

masukkan deskripsi gambar di sini

Cara lulus alat peraga

Berikut ini adalah kode untuk meneruskan alat peraga ke elemen anak:

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>

Bagaimana cara memancarkan acara

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
    }
  }
})

5
bagaimana jika fungsi 'kenaikan' ada di komponen induk dan saya ingin memicunya dari komponen anak?
Hamzaouiii

momen geser memahami konsep, meskipun telah menggunakannya beberapa kali oleh copy paste
hacky

1
Saya akan mencetak gambar itu dan menempelkannya di kepala saya. Terima kasih!
domih

1
Dalam contoh ini, bukankah kita harus memiliki pendengar acara yang didefinisikan dalam komponen root? Sesuatu seperti: `` `mount () {this.on ('increment', () => {this.incrementTotal ();}); } `` `
jmk2142

94

Dalam komponen anak:

this.$emit('eventname', this.variable)

Dalam komponen induk:

<component @eventname="updateparent"></component>

methods: {
    updateparent(variable) {
        this.parentvariable = variable
    }
}

3
Pikiranku hancur oleh contoh ini. Anda tidak tahu berapa tutorial yang saya lalui sebelum saya sampai di sini ...
suchislife

18

Komponen Anak

Gunakan this.$emit('event_name')untuk mengirim acara ke komponen induk.

masukkan deskripsi gambar di sini

Komponen Induk

Untuk mendengarkan peristiwa itu di komponen induk, kita lakukan v-on:event_namedan metode ( ex. handleChange) yang ingin kita jalankan pada peristiwa itu terjadi

masukkan deskripsi gambar di sini

Selesai :)


13

Saya setuju dengan acara memancarkan dan jawaban model-v untuk yang di atas. Namun, saya pikir saya akan memposting apa yang saya temukan tentang komponen dengan beberapa elemen bentuk yang ingin dipancarkan kembali ke induknya karena ini sepertinya salah satu artikel pertama yang dikembalikan oleh google.

Saya tahu pertanyaannya menentukan input tunggal, tetapi ini tampaknya paling cocok dan mungkin menghemat waktu orang dengan komponen vue yang serupa. Juga, belum ada yang menyebutkan .syncmodifikator.

Sejauh yang saya tahu, v-modelsolusinya hanya cocok untuk satu input yang kembali ke orangtua mereka. Saya mengambil sedikit waktu untuk mencarinya tetapi dokumentasi Vue (2.3.0) menunjukkan bagaimana cara menyinkronkan beberapa alat peraga yang dikirim ke komponen kembali ke induknya (tentu saja melalui emit).

Itu tepat disebut .syncpengubah.

Inilah yang dikatakan dalam dokumentasi :

Dalam beberapa kasus, kita mungkin membutuhkan "ikatan dua arah" untuk penyangga. Sayangnya, pengikatan dua arah yang benar dapat membuat masalah pemeliharaan, karena komponen anak dapat memutasi induk tanpa sumber dari mutasi itu menjadi jelas di kedua induk dan anak.

Karena itu, kami sarankan memancarkan acara dalam pola update:myPropName. Misalnya, dalam komponen hipotetis dengan titleprop, kita dapat mengomunikasikan maksud pemberian nilai baru dengan:

this.$emit('update:title', newTitle)

Kemudian orang tua dapat mendengarkan acara itu dan memperbarui properti data lokal, jika mau. Sebagai contoh:

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

Untuk kenyamanan, kami menawarkan singkatan untuk pola ini dengan pengubah .sync:

<text-document v-bind:title.sync="doc.title"></text-document>

Anda juga dapat menyinkronkan banyak sekaligus dengan mengirim melalui objek. Lihat dokumentasi di sini


Ini yang saya cari. Terima kasih banyak.
Thomas

Ini adalah solusi terbaik dan terkini pada tahun 2020. Terima kasih banyak!
Marcelo

6

Cara yang lebih sederhana adalah penggunaan this.$emit

Father.vue

<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>

Anak

<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>

Contoh lengkap saya: https://codesandbox.io/s/update-parent-property-ufj4b


5

Dimungkinkan juga untuk melewatkan alat peraga sebagai Obyek atau Array. Dalam hal ini data akan diikat dua arah:

(Ini dicatat di akhir topik: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow )

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;
    }
  }
});
<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>



0

1) Child Compnent: Anda dapat menggunakan seperti ini di komponen anak, tulis seperti ini: this.formValue adalah mengirim beberapa data ke komponen induk

this.$emit('send',this.formValue)

2) Parrent Compnenet: dan di parrent tag komponen menerima variabel kirim seperti ini: dan ini adalah kode untuk menerima bahwa data kompnen anak di tag komponen induk

@send="newformValue"

0

Cara lain adalah dengan memberikan referensi penyetel Anda dari induk sebagai penyangga ke komponen anak, mirip dengan cara mereka melakukannya di Bereaksi. Katakanlah, Anda memiliki sebuah metode updateValuepada orang tua untuk memperbarui nilai, Anda bisa instantiate komponen anak seperti: <child :updateValue="updateValue"></child>. Kemudian pada anak Anda akan memiliki prop sesuai: props: {updateValue: Function}, dan dalam template memanggil metode ketika input berubah: <input @input="updateValue($event.target.value)">.


0

Saya tidak tahu mengapa, tapi saya baru saja berhasil memperbarui data induk dengan menggunakan data sebagai objek, :set&computed

Parent.vue

<!-- check inventory status - component -->
    <CheckInventory :inventory="inventory"></CheckInventory>

data() {
            return {
                inventory: {
                    status: null
                },
            }
        },

Anak

<div :set="checkInventory">

props: ['inventory'],

computed: {
            checkInventory() {

                this.inventory.status = "Out of stock";
                return this.inventory.status;

            },
        }

0

contohnya akan memberi tahu Anda cara menyampaikan nilai input kepada orang tua pada tombol kirim.

Pertama, tentukan eventBus sebagai Vue baru.

//main.js
import Vue from 'vue';
export const eventBus = new Vue();

Pass your input value via Emit.
//Sender Page
import { eventBus } from "../main";
methods: {
//passing data via eventbus
    resetSegmentbtn: function(InputValue) {
        eventBus.$emit("resetAllSegment", InputValue);
    }
}

//Receiver Page
import { eventBus } from "../main";

created() {
     eventBus.$on("resetAllSegment", data => {
         console.log(data);//fetching data
    });
}

0

Saya pikir ini akan melakukan trik:

@change="$emit(variable)"

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.