การส่งผ่านข้อมูลไปยังคอมโพเนนต์ใน vue.js


92

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

ฉันหวังว่าจะได้รับความช่วยเหลือในการทำตัวอย่างง่ายๆ

  1. แสดงรายชื่อผู้ใช้ในองค์ประกอบเดียว (เสร็จสิ้น)
  2. ส่งข้อมูลผู้ใช้ไปยังส่วนประกอบใหม่เมื่อคลิกลิงก์ (เสร็จสิ้น) - ดูการอัปเดตที่ด้านล่าง
  3. แก้ไขข้อมูลผู้ใช้และส่งกลับไปยังองค์ประกอบดั้งเดิม (ยังไม่ได้รับข้อมูลนี้)

นี่คือซอซึ่งล้มเหลวในขั้นตอนที่สอง: https://jsfiddle.net/retrogradeMT/d1a8hps0/

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

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 สำหรับองค์ประกอบหลัก:

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 สำหรับองค์ประกอบที่สอง:

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

อัปเดต

โอเคฉันเข้าใจขั้นตอนที่สองแล้ว นี่คือซอใหม่ที่แสดงความคืบหน้า: https://jsfiddle.net/retrogradeMT/9pffnmjp/

เนื่องจากฉันใช้ Vue-router ฉันจึงไม่ใช้อุปกรณ์ประกอบฉากในการส่งข้อมูลไปยังส่วนประกอบใหม่ แต่ฉันต้องตั้งค่าพารามิเตอร์บน v-link จากนั้นใช้ตะขอเปลี่ยนเพื่อยอมรับ

การเปลี่ยนแปลง V-link ดูเส้นทางที่มีชื่อในเอกสารของ vue-router :

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

จากนั้นในส่วนประกอบให้เพิ่มข้อมูลไปยังตัวเลือกเส้นทางดูตะขอการเปลี่ยน :

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

คำตอบ:


46

------------- ต่อไปนี้ใช้ได้กับ Vue 1 เท่านั้น --------------

การส่งผ่านข้อมูลสามารถทำได้หลายวิธี วิธีการขึ้นอยู่กับประเภทการใช้งาน


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

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

ค่าเสานี้จะใช้ได้กับส่วนประกอบของคุณก็ต่อเมื่อคุณเพิ่มชื่อเสาprop-nameลงในpropsแอตทริบิวต์ของคุณ


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

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

และคุณต้องการที่จะส่งข้อมูลจาก<my-child-A>ไป<my-child-B>แล้ว<my-child-A>คุณจะต้องส่งกิจกรรม:

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

งานนี้จะเดินทางขึ้นเครือแม่ตลอด และจากผู้ปกครองรายใดที่คุณมีสาขาต่อ<my-child-B>คุณถ่ายทอดกิจกรรมพร้อมกับข้อมูล ดังนั้นในผู้ปกครอง:

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

ตอนนี้การออกอากาศนี้จะเดินทางไปตามห่วงโซ่เด็ก และไม่ว่าเด็กคนไหนที่คุณต้องการเข้าร่วมกิจกรรมในกรณีของ<my-child-B>เราเราจะเพิ่มกิจกรรมอื่น:

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

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


ตัดสินใจว่าคุณต้องการสื่อสารข้อมูลประเภทใดและเลือกให้เหมาะสม


1
ขอบคุณที่เป็นประโยชน์จริงๆ สิ่งเดียวที่ฉันยังคงดิ้นรนคือหลักการตั้งชื่อ เช่น: ฉันมี user.name ซึ่งฉันส่งผ่าน v-link เป็นชื่อ ตอนนี้ฉันสามารถแก้ไขตัวแปรชื่อและส่งกลับไปยังองค์ประกอบเดิมเป็นชื่อได้ แต่ส่วนประกอบดั้งเดิมไม่มีชื่อเรียกแบบอื่น ฉันขาดอะไรไปที่นี่? ไม่สามารถส่งผ่านวัตถุผ่าน v-link ได้หรือไม่?
ถอยหลังเข้าคลอง

1
คุณกำลังส่งผ่านวัตถุไปแล้ว paramsเป็นวัตถุ คุณสามารถกำหนดคีย์ชื่อthis.user.nameในส่วนประกอบของคุณได้ สร้างซอถ้าคุณต้องการความช่วยเหลือและแจ้งให้เราทราบ ตรวจสอบสิ่งนี้: vuejs.github.io/vue-router/en/route.html
notANerdDev

อ่าตกลงฉันได้แล้ว ขอบคุณอีกครั้ง. ขอขอบคุณสำหรับความช่วยเหลือของคุณทำให้ทุกอย่างชัดเจนขึ้นมาก
ถอยหลังเข้าคลอง

6
คำตอบที่ยอดเยี่ยม แต่ตามที่ฉันเข้าใจจะใช้ไม่ได้กับ 2.0 เนื่องจากมีการเลิกใช้งานกิจกรรม
rix

2
ฉันชอบคำตอบ แต่ก็ได้รับความคิดเห็นและตั้งแต่ฉันทำงานกับ Vue 2 ฉันรู้สึกว่าฉันจะไม่สามารถใช้วิธีที่สองที่คุณแนะนำได้ กลัวถูกต้องหรือไม่?
Konrad Viltersten

23

วิธีที่ดีที่สุดในการส่งข้อมูลจากองค์ประกอบที่ผู้ปกครองให้เด็กใช้อุปกรณ์ประกอบฉาก

การส่งผ่านข้อมูลจากผู้ปกครองไปยังเด็กผ่าน props

  • ประกาศprops(อาร์เรย์หรือวัตถุ ) ในลูก
  • ส่งต่อให้เด็กผ่านทาง <child :name="variableOnParent">

ดูการสาธิตด้านล่าง:

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/vue@2.5.13/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>


การแก้ไขขนาดเล็ก: "<child-comp" แทน "<child" และ variableAtParent .. ส่งต่อไปยังเด็กผ่าน <child-comp: name = "variableAtParent">
muenalan

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

@StanSokolov ไม่เลย ฉันไม่ทำงานสำหรับอาร์เรย์ดู: jsfiddle.net/acdcjunior/q4mank05 หากอาร์เรย์ของคุณไม่มีปฏิกิริยาแสดงว่าคุณอาจประสบปัญหาด้านปฏิกิริยา ลองใช้Vue.setเพิ่มเติมที่นี่: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior

เกิดอะไรขึ้นถ้ามันไม่ตอบสนอง? แน่ใจว่ามีปฏิกิริยาโดยการอ้างอิงถูกแทนที่ด้วยอาร์เรย์ใหม่อย่างต่อเนื่อง Vue ไม่เผยแพร่ "การเปลี่ยนแปลงอ้างอิง" ให้กับเด็ก ๆ มีเพียงการเปลี่ยนแปลงค่าขององค์ประกอบที่เรียบง่าย ดังนั้นหากการอ้างอิงถึงอาร์เรย์ถูกเขียนทับในพาเรนต์เด็ก ๆ จะยังคงเห็นการอ้างอิงเดิม จะไม่มีทางรู้ว่าผู้ปกครองทำงานกับวัตถุอื่นแล้ว
Stan Sokolov

@StanSokolov ดูสิ่งนี้: jsfiddle.net/acdcjunior/ftmrne2hอาร์เรย์จะถูกแทนที่ในพาเรนต์และเด็กจะเห็น / ตอบสนองต่อมัน (คลิกปุ่มเพื่อทดสอบ) หรือคุณหมายถึงอย่างอื่น? ถ้าเป็นเช่นนั้นจะเป็นประโยชน์หากคุณแก้ไขซอเพื่อแสดง
acdcjunior

15

ฉันคิดว่าปัญหาอยู่ที่นี่:

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

เมื่อคุณใส่คำนำหน้า prop พร้อมกับ:แสดงว่า Vue เป็นตัวแปรไม่ใช่สตริง ดังนั้นคุณไม่ต้องการสิ่ง{{}}รอบuser.nameข้าง ลอง:

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

แก้ไข -----

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


ขอบคุณเจฟฟ์ ฉันพยายามลบ {{}} แต่ก็ยังคงได้รับข้อผิดพลาดเดิม
ถอยหลังเข้าคลอง

2

ฉันพบวิธีส่งข้อมูลหลักไปยังขอบเขตส่วนประกอบใน Vue ฉันคิดว่ามันเป็นการแฮ็กเล็กน้อย แต่อาจจะช่วยคุณได้

1) ข้อมูลอ้างอิงใน Vue Instance เป็นวัตถุภายนอก (data : dataObj)

2) จากนั้นในฟังก์ชันการส่งคืนข้อมูลในองค์ประกอบลูกเพียงแค่ส่งคืนparentScope = dataObjและ voila ตอนนี้คุณสามารถทำสิ่งต่างๆเช่น{{ parentScope.prop }}และจะทำงานได้อย่างมีเสน่ห์

โชคดี!


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

1

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

รองรับ 2 องค์ประกอบ: CompA & CompB ที่มีพาเรนต์เดียวกันและ main.js สำหรับการตั้งค่าแอพ main vue สำหรับการส่งผ่านข้อมูลจาก CompA ไปยัง CompB โดยไม่ต้องเกี่ยวข้องกับองค์ประกอบหลักคุณสามารถทำสิ่งต่อไปนี้ได้

ในไฟล์ main.js ให้ประกาศอินสแตนซ์ Vue ส่วนกลางแยกต่างหากซึ่งจะเป็นบัสเหตุการณ์

export const bus = new Vue();

ใน CompA ซึ่งเหตุการณ์ถูกสร้างขึ้น: คุณต้องส่งเหตุการณ์ไปที่บัส

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

ตอนนี้งานคือการฟังเหตุการณ์ที่ปล่อยออกมาดังนั้นใน CompB คุณสามารถฟังได้

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

ข้อดี:

  • รหัสน้อยและสะอาด
  • ผู้ปกครองไม่ควรมีส่วนร่วมในการส่งต่อข้อมูลจากคอมพ์ลูก 1 คนไปยังอีกเครื่องหนึ่ง (เมื่อเด็กมีจำนวนมากขึ้นก็จะยากที่จะรักษา)
  • ปฏิบัติตามแนวทาง pub-sub


-2

สามารถใช้ตัวแปร JS ส่วนกลาง (อ็อบเจ็กต์) เพื่อส่งผ่านข้อมูลระหว่างคอมโพเนนต์ ตัวอย่าง: การส่งผ่านข้อมูลจาก Ammlogin.vue ไปยัง Options.vue ใน Ammlogin.vue rspData ถูกตั้งค่าเป็นการตอบสนองจากเซิร์ฟเวอร์ ใน Options.vue การตอบสนองจากเซิร์ฟเวอร์พร้อมใช้งานผ่าน 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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.