vuejs อัพเดตข้อมูลพาเรนต์จากคอมโพเนนต์ชายด์


155

ฉันเริ่มเล่นกับ vuejs (2.0) ฉันสร้างหน้าง่าย ๆ ด้วยองค์ประกอบหนึ่งในนั้น เพจมีอินสแตนซ์ Vue หนึ่งอินสแตนซ์พร้อมข้อมูล ในหน้านั้นฉันลงทะเบียนและเพิ่มองค์ประกอบเป็น html input[type=text]องค์ประกอบที่มีหนึ่ง ฉันต้องการให้ค่านั้นสะท้อนถึงแม่ (อินสแตนซ์ Vue หลัก)

ฉันจะอัพเดทข้อมูลพาเรนต์ของส่วนประกอบได้อย่างไร ผ่านเสาที่ถูกผูกไว้จากผู้ปกครองไม่ดีและส่งคำเตือนไปยังคอนโซล พวกเขามีบางอย่างในเอกสารของพวกเขา แต่มันไม่ทำงาน


1
คุณสามารถเพิ่มรหัสที่คุณได้ลองแล้วซึ่งไม่ได้ผล
Saurabh

คำตอบ:


181

การรวมสองทางได้เลิกใช้แล้วใน Vue 2.0 เพื่อใช้สถาปัตยกรรมที่ขับเคลื่อนด้วยเหตุการณ์มากขึ้น โดยทั่วไปแล้วเด็กไม่ควรเปลี่ยนอุปกรณ์ประกอบฉาก แต่ควรมี$emitเหตุการณ์และให้ผู้ปกครองตอบกลับเหตุการณ์เหล่านั้น

v-modelในกรณีของคุณโดยเฉพาะคุณสามารถใช้องค์ประกอบที่กำหนดเองด้วย นี่เป็นไวยากรณ์พิเศษที่ช่วยให้สิ่งที่ใกล้เคียงกับการผูกสองทาง แต่จริงๆแล้วเป็นการจดชวเลขสำหรับสถาปัตยกรรมที่ขับเคลื่อนด้วยเหตุการณ์ที่อธิบายข้างต้น คุณสามารถอ่านได้ที่นี่ -> https://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events

นี่คือตัวอย่างง่ายๆ:

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>


เอกสารระบุว่า

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

เทียบเท่ากับ

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

นั่นคือเหตุผลที่เสาในเด็กจะต้องมีการตั้งชื่อค่าและทำไมความต้องการของเด็กถึง $ inputปล่อยเหตุการณ์ที่มีชื่อ


แรกขอบคุณสำหรับการตอบสนอง คุณช่วยขยายหรือชี้ไปที่เอกสารเกี่ยวกับเหตุการณ์ 'อินพุต' ได้ดีขึ้นได้ไหม ดูเหมือนว่าจะมีเหตุการณ์ในตัว
Gal Ziv

ฉันได้เพิ่มคำอธิบายและทำให้ลิงก์ไปยังเอกสารชัดเจนยิ่งขึ้น
asemahle

1
ฉันละเว้น "ค่า" สำหรับองค์ประกอบและฟังก์ชันที่สร้างขึ้นและยังใช้งานได้ คุณอธิบายได้ไหมว่าทำไมคุณถึงใช้มัน
xetra11

1
หากคุณไม่ได้เพิ่มเสาดังนั้นมันจะเป็นundefinedจนกว่าการเปลี่ยนแปลงครั้งแรก props: ['value']ดูซอนี้ที่ฉันได้แสดงความคิดเห็นออกมา แจ้งให้ทราบว่าค่าเริ่มต้นคือundefinedแทนที่จะhello: jsfiddle.net/asemahle/8Lrkfxj6 หลังจากการเปลี่ยนแปลงครั้งแรก Vue จะเพิ่ม prop แบบไดนามิกให้กับส่วนประกอบดังนั้นจึงทำงานได้
asemahle

ฉันอ่านที่ผ่านมาในเอกสาร ตัวอย่างการทำงานที่ยอดเยี่ยม +10 ถ้าฉันทำได้!
ดิน

121

จากเอกสาร :

ใน Vue.js ความสัมพันธ์ขององค์ประกอบพาเรนต์ - ลูกสามารถสรุปได้ว่าเป็นอุปกรณ์ประกอบฉากลงเหตุการณ์ที่เกิดขึ้น ผู้ปกครองส่งข้อมูลไปยังเด็กผ่านอุปกรณ์ประกอบฉากและเด็กส่งข้อความไปยังผู้ปกครองผ่านกิจกรรม มาดูกันว่าพวกเขาทำงานอย่างไรต่อไป

ป้อนคำอธิบายรูปภาพที่นี่

วิธีการส่งอุปกรณ์ประกอบฉาก

ต่อไปนี้เป็นรหัสที่จะส่งอุปกรณ์ประกอบฉากไปยังองค์ประกอบของเด็ก:

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

วิธีการปล่อยเหตุการณ์

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
จะเกิดอะไรขึ้นถ้าฟังก์ชั่น“ เพิ่มกำลัง” ในองค์ประกอบหลักและฉันต้องการเรียกใช้งานจากองค์ประกอบย่อย
Hamzaouiii

ช่วงเวลาแห่งการรับรู้ถึงแรงเฉือนแม้จะใช้มันหลายครั้งโดยการทำสำเนาแฮ็ก ...
Yordan Georgiev

1
ฉันจะพิมพ์กราฟิกนั้นและติดกับหัวของฉัน ขอบคุณ!
domih

1
ในตัวอย่างนี้เราไม่ควรกำหนด listener เหตุการณ์ไว้ในองค์ประกอบรูท สิ่งที่ต้องการ: `` `เมานท์ () {this.on ('การเพิ่มขึ้น', () => {this.incrementTotal ();}); } `` `
jmk2142

94

ในองค์ประกอบลูก:

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

ในองค์ประกอบหลัก:

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

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

3
ใจของฉันปลิวไปตามตัวอย่างนี้ คุณไม่รู้หรอกว่ามีบทเรียนอะไรบ้างก่อนที่ฉันจะมาถึงที่นี่ ...
suchislife

18

องค์ประกอบลูก

ใช้this.$emit('event_name')เพื่อส่งเหตุการณ์ไปยังองค์ประกอบหลัก

ป้อนคำอธิบายรูปภาพที่นี่

ส่วนประกอบหลัก

ในการรับฟังเหตุการณ์นั้นในองค์ประกอบหลักเราทำv-on:event_nameและเมธอด ( ex. handleChange) ที่เราต้องการเรียกใช้งานในเหตุการณ์นั้นเกิดขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

เสร็จแล้ว :)


13

ฉันเห็นด้วยกับการเปล่งเหตุการณ์และคำตอบ v-model สำหรับสิ่งที่กล่าวมาข้างต้น อย่างไรก็ตามฉันคิดว่าฉันจะโพสต์สิ่งที่ฉันพบเกี่ยวกับส่วนประกอบที่มีองค์ประกอบหลายรูปแบบที่ต้องการส่งกลับไปยังผู้ปกครองเนื่องจากนี่เป็นหนึ่งในบทความแรกที่ส่งคืนโดย google

ฉันรู้ว่าคำถามระบุอินพุตเดี่ยว แต่นี่ดูเหมือนจะเป็นการจับคู่ที่ใกล้เคียงที่สุดและอาจช่วยผู้คนได้ในเวลาเดียวกันด้วยองค์ประกอบ vue ที่คล้ายกัน นอกจากนี้ยังไม่มีใครพูดถึง.syncตัวดัดแปลง

เท่าที่ฉันรู้v-modelวิธีการแก้ปัญหาจะเหมาะกับหนึ่งอินพุตกลับไปที่ผู้ปกครอง ฉันใช้เวลาเล็กน้อยในการมองหา แต่เอกสารประกอบของ Vue (2.3.0) จะแสดงวิธีการซิงค์อุปกรณ์ประกอบฉากหลายชิ้นที่ส่งไปยังส่วนประกอบกลับไปยังผู้ปกครอง (ผ่านการปล่อยแน่นอน)

มันถูกเรียกว่าโมดิ.syncฟายเออร์อย่างเหมาะสม

นี่คือสิ่งที่เอกสารบอกว่า:

ในบางกรณีเราอาจต้องการ“ การผูกมัดแบบสองทาง” สำหรับเสา น่าเสียดายที่การผูกสองทางที่แท้จริงสามารถสร้างปัญหาการบำรุงรักษาได้เนื่องจากองค์ประกอบลูกสามารถกลายพันธุ์ผู้ปกครองได้โดยไม่ต้องมีแหล่งที่มาของการกลายพันธุ์นั้นชัดเจนทั้งในแม่และลูก

update:myPropNameนั่นเป็นเหตุผลที่แทนเราขอแนะนำให้เหตุการณ์เปล่งแสงในรูปแบบของ ตัวอย่างเช่นในองค์ประกอบสมมุติที่มี titleเสาเราสามารถสื่อสารความตั้งใจในการกำหนดค่าใหม่ด้วย:

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

จากนั้นผู้ปกครองสามารถฟังเหตุการณ์นั้นและอัปเดตคุณสมบัติข้อมูลท้องถิ่นหากต้องการ ตัวอย่างเช่น:

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

เพื่อความสะดวกเราขอเสนอชวเลขสำหรับรูปแบบนี้ด้วยตัวแก้ไข. sync:

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

คุณยังสามารถซิงค์หลายครั้งพร้อมกันโดยส่งผ่านวัตถุ ตรวจสอบเอกสารที่นี่


นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณมาก.
โทมัส

นี่คือทางออกที่ดีที่สุดและทันสมัยที่สุดจนถึงปี 2020 ขอบคุณมาก!
Marcelo

6

วิธีใช้ง่ายขึ้น 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>

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>

ตัวอย่างแบบเต็มของฉัน: https://codesandbox.io/s/update-parent-property-ufj4b


5

นอกจากนี้ยังเป็นไปได้ที่จะส่งอุปกรณ์ประกอบฉากเป็นวัตถุหรืออาร์เรย์ ในกรณีนี้ข้อมูลจะถูกรวมเข้ากับสองทาง:

(สิ่งนี้ถูกบันทึกไว้ที่ท้ายหัวข้อ: 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>


1

วิธีที่ถูกต้องคือการเหตุการณ์ในองค์ประกอบของเด็กที่อินสแตนซ์วูหลักฟังสำหรับ$emit()

// Child.js
Vue.component('child', {
  methods: {
    notifyParent: function() {
      this.$emit('my-event', 42);
    }
  }
});

// Parent.js
Vue.component('parent', {
  template: '<child v-on:my-event="onEvent($event)"></child>',
  methods: {
    onEvent: function(ev) {
      v; // 42
    }
  }
});

0

1) Child Compnent: คุณสามารถใช้สิ่งนี้ในองค์ประกอบลูกเขียนดังนี้: this.formValue คือการส่งข้อมูลไปยังองค์ประกอบหลัก

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

2) Parrent Compnenet: และในแท็กคอมโพเนนต์ parrent จะได้รับการส่งตัวแปรเช่นนี้: และนี่คือรหัสสำหรับรับที่เด็ก compnent ข้อมูลในแท็กองค์ประกอบหลัก

@send="newformValue"

0

อีกวิธีหนึ่งคือการส่งการอ้างอิงของ setter ของคุณจากพาเรนต์ไปเป็นส่วนประกอบไปยังส่วนย่อยของลูก บอกว่าคุณมีวิธีการที่ผู้ปกครองในการปรับปรุงค่าคุณสามารถยกตัวอย่างองค์ประกอบเด็กชอบโดย:updateValue <child :updateValue="updateValue"></child>จากนั้นในวันเด็กที่คุณจะมีความสอดคล้องกัน prop: และในแม่แบบเรียกวิธีเมื่อมีการเปลี่ยนแปลงการป้อนข้อมูล:props: {updateValue: Function}<input @input="updateValue($event.target.value)">


0

ฉันไม่รู้ว่าทำไม แต่ฉันเพิ่งอัปเดตข้อมูลหลักโดยใช้ข้อมูลเป็นวัตถุ:set&computed

Parent.vue

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

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

Child.vue

<div :set="checkInventory">

props: ['inventory'],

computed: {
            checkInventory() {

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

            },
        }

0

ตัวอย่างของเขาจะบอกวิธีส่งค่าอินพุตให้ผู้ปกครองเมื่อกดปุ่มส่ง

ก่อนอื่นให้กำหนด eventBus เป็น Vue ใหม่

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.