รับข้อมูลจากองค์ประกอบเดียว Vue ในองค์ประกอบอื่นหรือไม่

ฉันใช้ Vue.js 2.5.13 และมีโครงสร้างนี้:

ส่วนประกอบ-one.vue:

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two></component-two>
      </div>
    </template>

    <script>
      import ComponentTwo from 'component-two.vue'

      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ... // <-- I want to get value from ComponentTwo input_two (v-model) here
          }
        }
      }
    </script>

ส่วนประกอบ two.vue:

    <template>
      <div>
        <input type="text" v-model="input_two">
      </div>
    </template>

    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo'
          }
        }
      }
    </script>

วิธีรับข้อมูลจาก ComponentTwo ในองค์ประกอบ ComponentOne สิ่งนี้สำคัญสำหรับฉันเพราะฉันมีส่วนประกอบที่คล้ายกันมากมายพร้อมฟิลด์ (แบบฟอร์มไซต์การลงทะเบียนขนาดใหญ่) และไม่มีความคิดเกี่ยวกับการเรียกข้อมูลระหว่างส่วนประกอบ Vue


person koddr    schedule 29.01.2018    source แหล่งที่มา
comment
แชร์ข้อมูลระหว่างคอมโพเนนต์ต่างๆ ใน ​​Vuejs อาจซ้ำกัน   -  person Roy J    schedule 29.01.2018
comment
@RoyJ - ฉันไม่คิดว่าฉันจะอ้างอิงสิ่งนั้นว่าซ้ำกันที่เป็นไปได้เนื่องจากคำตอบนั้นเสนอโดยใช้ตัวดัดแปลง .sync ซึ่งมี ถูกลบออกจาก vue แล้ว แต่แน่นอนว่ามีคำถามอื่นๆ มากมายที่ผู้ให้บริการตอบสำหรับสถานการณ์นี้   -  person PatrickSteele    schedule 29.01.2018


คำตอบ (5)


คุณสามารถบรรลุเป้าหมายนี้ได้อย่างง่ายดายโดยใช้บัสเหตุการณ์ทั่วโลก

https://alligator.io/vuejs/global-event-bus/

สำหรับแอปพลิเคชันขนาดใหญ่และซับซ้อนมากขึ้น ฉันขอแนะนำให้ใช้เครื่องมือการจัดการสถานะ เช่น vuex

https://vuex.vuejs.org/en/

person Community    schedule 29.01.2018

Vuejs ใช้ "อุปกรณ์ประกอบฉาก" สำหรับการสื่อสารระหว่างผู้ปกครอง/เด็ก และ "ปล่อย" เหตุการณ์ สำหรับเด็ก/การสื่อสารของผู้ปกครอง

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

คุณต้องจำไว้ว่าสำหรับทุกอุปกรณ์ประกอบฉากที่คุณส่งผ่านไปยังองค์ประกอบย่อย คุณควรมีอุปกรณ์ประกอบฉากนั้นไปยังอาร์เรย์อุปกรณ์ประกอบฉาก เช่นเดียวกับเหตุการณ์ ทุกเหตุการณ์ที่คุณปล่อยออกมาคุณควรจับในองค์ประกอบหลัก ดังนั้น:

ส่วนประกอบ-one.vue:

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two
            @CustomEventInputChanged="doSomenthing">
        </component-two>
      </div>
    </template>

    <script>
      import ComponentTwo from 'component-two.vue'

      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ''
          }
        },
        methods: {
            doSomenthing ( data ) {
                this.input_two = data;
            }
        }
      }
    </script>

ส่วนประกอบ two.vue:

    <template>
      <div>
        <input type="text" v-model="input_two" @change="emitEventChanged>
      </div>
    </template>

    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo'
          }
        },
        methods: {
            emitEventChanged () {
                this.$emit('CustomEventInputChanged', this.input_two);
            }
        }

      }
    </script>

สิ่งนี้ควรจะได้ผล

person Luca Giardina    schedule 29.01.2018

คุณต้องใช้ระบบที่ส่ง v-model กลับไปยังพาเรนต์

ซึ่งสามารถทำได้โดยใช้คุณสมบัติที่คำนวณภายใน component-two ที่ส่งเสียงการเปลี่ยนแปลงภายในวิธีการที่กำหนดไว้

ตัวอย่าง:

Vue.component('component-two', {
  name: 'component-two',
  template: '#component-two-template',
  props: {
    value: {
      required: true,
      type: String,
    },
  },
  computed: {
    message: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      },
    },
  },
});

var app = new Vue({
  el: '#app',
  data: {
    message1: 'm1',
    message2: 'm2',
  },
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script type="text/x-template" id="component-two-template">
  <input type="text" v-model="message"/>
</script>
<div id="app">
  <input type="text" v-model="message1"/>
  <component-two v-model="message2"></component-two>
  <p>Output</p>
  <pre>{{message1}}</pre>
  <pre>{{message2}}</pre>
</div>

person Ferrybig    schedule 29.01.2018

มีหลายวิธีในการดำเนินการ และบางวิธีมีการกล่าวถึงในคำตอบอื่นๆ:
(ไม่เรียงลำดับใดเป็นพิเศษ อ่านข้อมูลเพิ่มเติมในส่วนรายละเอียดด้านล่าง)

  1. ใช้ eventbus ทั่วโลก
  2. ใช้ อุปกรณ์ประกอบฉากในส่วนประกอบ
  3. ใช้ แอตทริบิวต์ v-model
  4. ใช้ตัวแก้ไขการซิงค์
  5. ใช้ Vuex

สำหรับการเชื่อมโยงแบบสองทาง โปรดจำไว้ว่าอาจทำให้เกิดการกลายพันธุ์ต่อเนื่องซึ่งยากต่อการรักษา โดยอ้างอิงจากเอกสาร:

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

ต่อไปนี้เป็นรายละเอียดเกี่ยวกับวิธีการต่างๆ ที่มีอยู่:

1.) ใช้ eventbus ทั่วโลก

ฉัน แนะนำอย่างยิ่งไม่ให้ ใช้วิธีการนี้สำหรับการสื่อสารทั่วไปทุกประเภทระหว่างส่วนประกอบต่างๆ ตามที่ได้มีการพูดคุยกันในหลาย ๆ ที่เช่น ที่นี่

2.) ใช้อุปกรณ์ประกอบฉากกับส่วนประกอบ

อุปกรณ์ประกอบฉากใช้งานง่ายและเป็นวิธีที่เหมาะสมที่สุดในการแก้ปัญหาที่พบบ่อยที่สุด
เนื่องจาก วิธีที่ Vue สังเกตการเปลี่ยนแปลง คุณสมบัติทั้งหมดจำเป็นต้องมีอยู่บนวัตถุ ไม่เช่นนั้นจะไม่เกิดปฏิกิริยา หากมีการเพิ่มคุณสมบัติใดๆ หลังจากที่ Vue ทำให้ 'set' สามารถมองเห็นได้เสร็จสิ้นแล้ว จะต้อง ถูกนำมาใช้

 //Normal usage
 Vue.set(aVariable, 'aNewProp', 42);
 //This is how to use it in Nuxt
 this.$set(this.historyEntry, 'date', new Date());

วัตถุจะมีปฏิกิริยาสำหรับทั้งส่วนประกอบและพาเรนต์:

ฉันส่งวัตถุ/อาร์เรย์เป็นเสา มันเป็นการซิงค์แบบสองทางโดยอัตโนมัติ - เปลี่ยนข้อมูลในลูก มันเปลี่ยนในพาเรนต์

หากคุณส่งค่าง่าย ๆ (สตริง, ตัวเลข) ผ่านอุปกรณ์ประกอบฉาก คุณจะต้องใช้ ตัวแก้ไข .sync

ตามที่ยกมาจาก --> https://stackoverflow.com/a/35723888/1087372

3.) ใช้แอตทริบิวต์ v-model

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

นี้:

 <input v-model="searchText">

เหมือนกับสิ่งนี้:

 <input
   v-bind:value="searchText"
   v-on:input="searchText = $event.target.value"
 >

โดยที่เสาต้องเป็น ค่า และเหตุการณ์จะต้องเป็น อินพุต

4.) ใช้ตัวแก้ไขการซิงค์

ตัวปรับแต่งการซิงค์ยังเป็นน้ำตาลเชิงวากยสัมพันธ์และทำหน้าที่เหมือนกับ v-model เพียงแต่ว่าชื่อพร็อพและเหตุการณ์จะถูกตั้งค่าตามสิ่งที่กำลังใช้งานอยู่

ในพาเรนต์นั้นสามารถใช้ได้ดังนี้:

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

จากเด็ก สามารถส่งเหตุการณ์เพื่อแจ้งให้ผู้ปกครองทราบถึงการเปลี่ยนแปลงใดๆ:

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

5.) ใช้ Vuex

Vuex เป็นที่เก็บข้อมูลที่สามารถเข้าถึงได้จากทุกองค์ประกอบ สามารถสมัครรับการเปลี่ยนแปลงได้

การใช้ร้านค้า Vuex ทำให้ง่ายต่อการดูโฟลว์ของการกลายพันธุ์ของข้อมูลและมีการกำหนดไว้อย่างชัดเจน การใช้เครื่องมือสำหรับนักพัฒนา vue ทำให้ง่ายต่อการดีบักและย้อนกลับการเปลี่ยนแปลงที่ทำขึ้น

แนวทางนี้จำเป็นต้องใช้ต้นแบบเพิ่มเติมอีกเล็กน้อย แต่หากใช้ทั่วทั้งโปรเจ็กต์ จะเป็นวิธีที่สะอาดกว่ามากในการพิจารณาว่าจะทำการเปลี่ยนแปลงอย่างไรและจากที่ใด

ดูคู่มือเริ่มต้นใช้งาน

person SanBen    schedule 30.04.2020

คุณสามารถใช้ .sync Modifier ได้

<template>
  <div>
    <input type="text" v-model="input_one">
    <component-two :secondValue.sync="input_two"></component-two>
  </div>
</template>

<script>
  import ComponentTwo from 'component-two.vue'

  export default {
    name: "component-one",
    components: {
      ComponentTwo
    },
    data() {
      return {
        input_one: 'Hello from ComponentOne',
        input_two: ''
      }
    }
  }
</script>

องค์ประกอบ two.vue:

<template>
  <div>
    <input type="text" v-model="input_two">
  </div>
</template>

<script>
  export default {
    name: "component-two",
    data() {
      return {
        input_one: 'Hello from ComponentTwo',
        input_two: ''
      },
      watch: {
        input_two : function(val){
          this.$emit('update:secondValue', val)
        }
      }
    }
  }
</script>
person El Danielo    schedule 29.01.2018