ChatGPT解决这个技术问题 Extra ChatGPT

Passing data to components in vue.js

I'm struggling to understand how to pass data between components in vue.js. I have read through the docs several times and looked at many vue related questions and tutorials, but I'm still not getting it.

To wrap my head around this, I am hoping for help completing a pretty simple example

display a list of users in one component (done) send the user data to a new component when a link is clicked (done) - see update at bottom. edit user data and send it back to original component (haven't gotten this far)

Here is a fiddle, which fails on step two: https://jsfiddle.net/retrogradeMT/d1a8hps0/

I understand that I need to use props to pass data to the new component, but I'm not sure how to functionally do it. How do I bind the data to the new component?

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 for main component:

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 for second component:

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

UPDATE

Ok, I've got the second step figured out. Here is a new fiddle showing the progress: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Because I'm using Vue-router, I don't use props to send the data to a new component. Instead, I need set params on the v-link and then use a transition hook to accept it.

V-link changes see named routes in vue-router docs:

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

Then on the component, add data to the route options see transition hooks:

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

n
notANerdDev

-------------Following is applicable only to Vue 1 --------------

Passing data can be done in multiple ways. The method depends on the type of use.

If you want to pass data from your html while you add a new component. That is done using props.

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

This prop value will be available to your component only if you add the prop name prop-name to your props attribute.

When data is passed from a component to another component because of some dynamic or static event. That is done by using event dispatchers and broadcasters. So for example if you have a component structure like this:

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

And you want to send data from <my-child-A> to <my-child-B> then in <my-child-A> you will have to dispatch an event:

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

This event will travel all the way up the parent chain. And from whichever parent you have a branch toward <my-child-B> you broadcast the event along with the data. So in the parent:

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

Now this broadcast will travel down the child chain. And at whichever child you want to grab the event, in our case <my-child-B> we will add another event:

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

The third way to pass data is through parameters in v-links. This method is used when components chains are completely destroyed or in cases when the URI changes. And i can see you already understand them.

Decide what type of data communication you want, and choose appropriately.


Thank you, that was really helpful. The only piece I'm still struggling with is naming conventions. i.e: I have user.name which I pass via v-link as name. I can now edit the name variable and pass it back to the original component as name, but the original component doesn't have a var called name. What am I missing here? Doesn't appear possible to pass an object through v-link?
You are already passing an object. params is an object. The name key can be assigned to this.user.name in your component. Create a fiddle if you need help, and let me know. Check this out: vuejs.github.io/vue-router/en/route.html
Ah, ok I've got it now. Thanks again. I appreciate your help, it really made things much clearer.
Awesome answer but as i understand it will not work with 2.0 as events has been deprecated?
I loved the answer but then got to the comments and since I'm working with Vue 2, I sense that I'm not going to be able the second method suggested by you. Is that correctly feared?
t
tony19

The best way to send data from a parent component to a child is using props.

Passing data from parent to child via props

Declare props (array or object) in the child

Pass it to the child via

See demo below:

Vue.component('child-comp', { props: ['message'], // declare the props template: '

At child-comp, using props in the template: {{ message }}

', mounted: function () { console.log('The props are also available in JS:', this.message); } }) new Vue({ el: '#app', data: { variableAtParent: 'DATA FROM PARENT!' } })

At Parent: {{ variableAtParent }}
And is reactive (edit it)


small fix: "
It only will work with simple property, object references will not be updated. For example if you have parent property be array, and this array got replaced in parent object to another array, child will not see it.
@StanSokolov not at all. I does work for arrays, see: jsfiddle.net/acdcjunior/q4mank05 . If you array is not reactive, you probably are facing a reactivity issue. Try using Vue.set, more here: vuejs.org/v2/guide/reactivity.html#For-Arrays
What the point if it is not reactive ? Sure it was reactive with reference constantly replaced by a new array. Vue does not propagate "reference changes" to children, only value changes on simple elements. So if reference to array was overwritten in parent, children will still see the old reference. Will never know parent now works with a different object.
@StanSokolov See this: jsfiddle.net/acdcjunior/ftmrne2h the array is replaced in parent and the child sees/reacts to it (click the button to test). Or do you mean something else? If so, it would be helpful if you edit the fiddle to show it
J
Jeff

I think the issue is here:

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

When you prefix the prop with : you are indicating to Vue that it is a variable, not a string. So you don't need the {{}} around user.name. Try:

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

EDIT-----

The above is true, but the bigger issue here is that when you change the URL and go to a new route, the original component disappears. In order to have the second component edit the parent data, the second component would need to be a child component of the first one, or just a part of the same component.


Thanks jeff. I tried to remove the {{}} but I still get the same errors.
B
Brane

I've found a way to pass parent data to component scope in Vue, i think it's a little a bit of a hack but maybe this will help you.

1) Reference data in Vue Instance as an external object (data : dataObj)

2) Then in the data return function in the child component just return parentScope = dataObj and voila. Now you cann do things like {{ parentScope.prop }} and will work like a charm.

Good Luck!


Thats coupling both components together what can be okay for a tree and his nodes, but is normally not favored. I would try to avoid this.
D
Divesh Sahu

The above-mentioned responses work well but if you want to pass data between 2 sibling components, then the event bus can also be used. Check out this blog which would help you understand better.

supppose for 2 components : CompA & CompB having same parent and main.js for setting up main vue app. For passing data from CompA to CompB without involving parent component you can do the following.

in main.js file, declare a separate global Vue instance, that will be event bus.

export const bus = new Vue();

In CompA, where the event is generated : you have to emit the event to bus.

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

Now the task is to listen the emitted event, so, in CompB, you can listen like.

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

Advantages:

Less & Clean code.

Parent should not involve in passing down data from 1 child comp to another ( as the number of children grows, it will become hard to maintain )

Follows pub-sub approach.


T
T.Todua

I access main properties using $root.

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

K
Kjelle J

A global JS variable (object) can be used to pass data between components. Example: Passing data from Ammlogin.vue to Options.vue. In Ammlogin.vue rspData is set to the response from the server. In Options.vue the response from the server is made available via 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>