Truyền dữ liệu đến các thành phần trong vue.js


92

Tôi đang đấu tranh để hiểu cách truyền dữ liệu giữa các thành phần trong vue.js. Tôi đã đọc qua tài liệu nhiều lần và xem nhiều câu hỏi và hướng dẫn liên quan đến vue, nhưng tôi vẫn không hiểu.

Để giải quyết vấn đề này, tôi hy vọng được giúp đỡ để hoàn thành một ví dụ khá đơn giản

  1. hiển thị danh sách người dùng trong một thành phần (đã xong)
  2. gửi dữ liệu người dùng đến một thành phần mới khi một liên kết được nhấp vào (xong) - xem bản cập nhật ở dưới cùng.
  3. chỉnh sửa dữ liệu người dùng và gửi nó trở lại thành phần ban đầu (chưa đi được xa)

Đây là một fiddle, không thành công ở bước hai: https://jsfiddle.net/retrogradeMT/d1a8hps0/

Tôi hiểu rằng tôi cần sử dụng đạo cụ để chuyển dữ liệu sang thành phần mới, nhưng tôi không chắc về cách thực hiện chức năng. Làm cách nào để liên kết dữ liệu với thành phần mới?

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 cho thành phần chính:

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 cho thành phần thứ hai:

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

CẬP NHẬT

Được rồi, tôi đã tìm ra bước thứ hai. Đây là một trò chơi mới cho thấy tiến trình: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Bởi vì tôi đang sử dụng Vue-router, tôi không sử dụng đạo cụ để gửi dữ liệu đến một thành phần mới. Thay vào đó, tôi cần thiết lập các tham số trên v-link và sau đó sử dụng móc chuyển tiếp để chấp nhận nó.

Thay đổi V-link xem các tuyến đường được đặt tên trong tài liệu vue-router :

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

Sau đó, trên thành phần, thêm dữ liệu vào các tùy chọn tuyến đường xem các móc chuyển tiếp :

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

Câu trả lời:


46

------------- Sau đây chỉ áp dụng cho Vue 1 --------------

Việc truyền dữ liệu có thể được thực hiện theo nhiều cách. Phương pháp phụ thuộc vào loại sử dụng.


Nếu bạn muốn chuyển dữ liệu từ html của mình trong khi bạn thêm một thành phần mới. Điều đó được thực hiện bằng cách sử dụng đạo cụ.

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

Giá trị prop này sẽ chỉ có sẵn cho thành phần của bạn nếu bạn thêm tên prop prop-namevào propsthuộc tính của mình .


Khi dữ liệu được truyền từ một thành phần này sang thành phần khác vì một số sự kiện động hoặc tĩnh. Điều đó được thực hiện bằng cách sử dụng người điều phối và phát sóng sự kiện. Vì vậy, ví dụ nếu bạn có cấu trúc thành phần như thế này:

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

Và bạn muốn gửi dữ liệu từ đó <my-child-A>đến <my-child-B>đó, <my-child-A>bạn sẽ phải gửi một sự kiện:

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

Sự kiện này sẽ diễn ra xuyên suốt chuỗi mẹ. Và từ bất kỳ nguồn gốc nào mà bạn có nhánh hướng tới <my-child-B>bạn sẽ phát sự kiện cùng với dữ liệu. Vì vậy, trong cha mẹ:

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

Bây giờ chương trình phát sóng này sẽ đi xuống chuỗi con. Và ở bất kỳ con nào bạn muốn lấy sự kiện, trong trường hợp của <my-child-B>chúng tôi, chúng tôi sẽ thêm một sự kiện khác:

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

Cách thứ ba để truyền dữ liệu là thông qua các tham số trong liên kết v. Phương pháp này được sử dụng khi chuỗi thành phần bị phá hủy hoàn toàn hoặc trong trường hợp URI thay đổi. Và tôi có thể thấy bạn đã hiểu chúng.


Quyết định loại giao tiếp dữ liệu bạn muốn và chọn một cách thích hợp.


1
Cảm ơn bạn, điều đó thực sự hữu ích. Phần duy nhất tôi vẫn đang đấu tranh là các quy ước đặt tên. tức là: Tôi có user.name mà tôi chuyển qua v-link làm tên. Bây giờ tôi có thể chỉnh sửa biến tên và chuyển nó trở lại thành phần ban đầu dưới dạng tên, nhưng thành phần ban đầu không có tên var được gọi. Tôi còn thiếu gì ở đây? Dường như không thể chuyển một đối tượng thông qua liên kết v?
ngược lại

1
Bạn đã chuyển một đối tượng. paramslà một đối tượng. Khóa tên có thể được chỉ định this.user.nametrong thành phần của bạn. Tạo một trò chơi nếu bạn cần trợ giúp và cho tôi biết. Hãy kiểm tra này: vuejs.github.io/vue-router/en/route.html
notANerdDev

À, được rồi, tôi đã có nó bây giờ. Cảm ơn một lần nữa. Tôi đánh giá cao sự giúp đỡ của bạn, nó thực sự làm cho mọi thứ rõ ràng hơn nhiều.
ngược

6
Câu trả lời tuyệt vời nhưng theo tôi hiểu, nó sẽ không hoạt động với 2.0 vì các sự kiện không được dùng nữa?
rix

2
Tôi thích câu trả lời nhưng sau đó đã nhận xét và vì tôi đang làm việc với Vue 2, tôi cảm thấy rằng tôi sẽ không thể thực hiện phương pháp thứ hai do bạn đề xuất. Điều đó có chính xác là sợ hãi?
Konrad Viltersten

23

Cách tốt nhất để gửi dữ liệu từ thành phần mẹ đến thành phần con là sử dụng đạo cụ .

Truyền dữ liệu từ cha mẹ sang con qua props

  • Khai báo props(mảng hoặc đối tượng ) trong con
  • Truyền nó cho đứa trẻ qua <child :name="variableOnParent">

Xem demo bên dưới:

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>


sửa chữa nhỏ: "<con-comp" thay vì "<đứa trẻ" và variableAtParent .. Vượt qua nó cho đứa trẻ qua <trẻ em comp: name = "variableAtParent">
muenalan

Nó chỉ hoạt động với thuộc tính đơn giản, các tham chiếu đối tượng sẽ không được cập nhật. Ví dụ: nếu bạn có thuộc tính cha là mảng, và mảng này đã được thay thế trong đối tượng mẹ thành một mảng khác, con sẽ không nhìn thấy nó.
Stan Sokolov

@StanSokolov không hề. Tôi làm việc cho các mảng, hãy xem: jsfiddle.net/acdcjunior/q4mank05 . Nếu mảng của bạn không hoạt động, có thể bạn đang gặp phải vấn đề về khả năng phản ứng. Hãy thử sử dụng Vue.set, thêm tại đây: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior

Điều gì sẽ xảy ra nếu nó không phản ứng? Chắc chắn nó đã phản ứng với tham chiếu liên tục được thay thế bằng một mảng mới. Vue không tuyên truyền "tham chiếu thay đổi" cho trẻ em, chỉ đánh giá các thay đổi trên các yếu tố đơn giản. Vì vậy, nếu tham chiếu đến mảng đã được ghi đè trong cha mẹ, con sẽ vẫn thấy tham chiếu cũ. Sẽ không bao giờ biết cha mẹ bây giờ làm việc với một đối tượng khác.
Stan Sokolov

@StanSokolov Xem phần này: jsfiddle.net/acdcjunior/ftmrne2h mảng được thay thế trong phần cha và phần con nhìn thấy / phản ứng với nó (nhấp vào nút để kiểm tra). Hay bạn ám chỉ điều gì khác? Nếu vậy, sẽ rất hữu ích nếu bạn chỉnh sửa fiddle để hiển thị nó
acdcjunior

15

Tôi nghĩ vấn đề nằm ở đây:

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

Khi bạn đặt tiền tố prop với :bạn đang chỉ cho Vue rằng nó là một biến, không phải một chuỗi. Vì vậy, bạn không cần {{}}xung quanh user.name. Thử:

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

BIÊN TẬP-----

Điều trên là đúng, nhưng vấn đề lớn hơn ở đây là khi bạn thay đổi URL và đi đến một tuyến đường mới, thành phần ban đầu sẽ biến mất. Để có thành phần thứ hai chỉnh sửa dữ liệu mẹ, thành phần thứ hai cần phải là thành phần con của thành phần đầu tiên hoặc chỉ là một phần của cùng một thành phần.


Cảm ơn jeff. Tôi đã cố xóa dấu {{}} nhưng vẫn gặp lỗi tương tự.
ngược lại

2

Tôi đã tìm thấy một cách để chuyển dữ liệu mẹ sang phạm vi thành phần trong Vue, tôi nghĩ rằng nó hơi khó một chút nhưng có thể điều này sẽ giúp bạn.

1) Dữ liệu tham chiếu trong Vue Instance như một đối tượng bên ngoài (data : dataObj)

2) Sau đó trong hàm trả về dữ liệu trong thành phần con chỉ cần trả về parentScope = dataObjvà thì đấy. Bây giờ bạn không thể làm những điều thích {{ parentScope.prop }}và sẽ hoạt động như một sự quyến rũ.

Chúc may mắn!


Đó là kết hợp cả hai thành phần với nhau những gì có thể ổn cho một cây và các nút của nó, nhưng thường không được ưa chuộng. Tôi sẽ cố gắng tránh điều này.
tháng

1

Các phản hồi được đề cập ở trên hoạt động tốt nhưng nếu bạn muốn truyền dữ liệu giữa 2 thành phần anh em, thì bus sự kiện cũng có thể được sử dụng. Kiểm tra blog này sẽ giúp bạn hiểu rõ hơn.

giả sử cho 2 thành phần: CompA & CompB có cùng nguồn gốc và main.js để thiết lập ứng dụng vue chính. Để chuyển dữ liệu từ CompA sang CompB mà không liên quan đến thành phần mẹ, bạn có thể làm như sau.

trong tệp main.js, khai báo một cá thể Vue toàn cục riêng biệt, đó sẽ là bus sự kiện.

export const bus = new Vue();

Trong CompA, nơi sự kiện được tạo: bạn phải phát sự kiện ra bus.

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

Bây giờ nhiệm vụ là lắng nghe sự kiện được phát ra, vì vậy, trong CompB, bạn có thể nghe như thế nào.

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

Ưu điểm:

  • Ít hơn và sạch mã.
  • Cha mẹ không nên tham gia vào việc chuyển dữ liệu từ bộ phận này sang bộ phận khác (khi số lượng trẻ tăng lên, nó sẽ trở nên khó duy trì)
  • Thực hiện theo cách tiếp cận pub-sub.

0

Tôi truy cập các thuộc tính chính bằng cách sử dụng $root.

Vue.component("example", { 
    template: `<div>$root.message</div>`
});
...
<example></example>

-2

Một biến JS chung (đối tượng) có thể được sử dụng để truyền dữ liệu giữa các thành phần. Ví dụ: Truyền dữ liệu từ Ammlogin.vue sang Options.vue. Trong Ammlogin.vue rspData được đặt thành phản hồi từ máy chủ. Trong Options.vue, phản hồi từ máy chủ được cung cấp thông qua 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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.