简体   繁体   中英

Call parent methods from child components (Vue.js)

I'm doing a project and I need to call parent methods from child components. How can this be accomplished in Vue.js?

You should use this.$emit('myEvent') inside of your child component, when you want to trigger the method in the parent.

Then find your child component in the template of the parent and add an event catcher on it like this:

<template>
  <your-child-component @myEvent="myMethod"/>
</template>

If you want to add parameters to your method, you can add a second parameter to your emit like this:

this.$emit("myEvent", "My parameter")

For this to work you don't have to change anything in the event "catcher", as long as the method you call has a parameter.

道具和发射

Maybe working example will make it more clear.

https://m-vue-leaflet.netlify.app/

code- https://github.com/manojkmishra/vue-leaflet-mapping

So here if you see there are 3 vue files in components folder. Brew.vue is parent component to BrewList.vue child component.

Brew.vue- Parent Component

父组件

BrewList.vue - Child Component

子组件

Child component BrewList.vue is using emit to send mouse-over-brew & mouse-leave-brew values to parent Brew.vue. Also, in case you are interested Brew.vue parent is sending brew prop to BrewList.vue child.

子级向父级发射

As per docs- https://v2.vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events

Dec, 2021 Update:

It works with $emit . The name of @ callTest in parent component must be same as the name of $emit(' callTest ') in child component.

Parent Component :

<template>
  <Child
    @callTest="test" // Assign 'test' method to @callTest
  />
</template>

<script>
import Child from "../components/Child.vue";
import { defineComponent } from "vue";

export default defineComponent({
  name: "Parent",

  components: {
    Child,
  },

  methods: {
    test() {
      alert("Test");
    },
  }
});
</script>

Child Component :

<template>
  <button @click="$emit('callTest')">Click Me</button>
</template>

<script>
import { defineComponent } from "vue";
    
export default defineComponent({
  name: "Child",
});
</script>

Again, the name of @ callTest in parent component must be same as the name of $emit(' callTest ') in child component.


If you use $emit in script section, this is needed different from template section.

Child Component :

<template>
  <button @click="message">Click Me</button>
</template>

<script>
import { defineComponent } from "vue";
    
export default defineComponent({
  name: "Child",
  methods: {
    message() {
      this.$emit('callTest') // 'this' is needed.
    }
  }
});
</script>

If test method has 2 parameters , you need to call test method with 2 arguments in child component like below.

Parent Component :

<template>
  <Child
    @callTest="test" // Assign 'test' method to @callTest
  />
</template>

<script>
import Child from "../components/Child.vue";
import { defineComponent } from "vue";

export default defineComponent({
  name: "Parent",

  omponents: {
    Child,
  },
        
  methods: {
    test(num1, num2) { // 'test' method has 2 parameters.
      alert(num1 + num2);
    },
  }
});
</script>

Child Component :

<template>       // Call 'test' method with 2 arguments.                          
  <button @click="$emit('callTest', 3, 5)">Click Me</button>
</template>

<script>
import { defineComponent } from "vue";
        
export default defineComponent({
  name: "Child",
});
</script>

Ideally, this is the right way to do so: https://v2.vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events

On the other hand, I believe in your scenario (which I'm trying to assume cause it's not really clear), you can use this.$parent.methodName.

Keep in mind that the second suggestion is less clean. It should be used just in case of need.

So basically, there are 2 ways to answer your question

  1. Using $emit , with syntax is @

  2. Passing function as props , with syntax is : The same as your example

If you based on Vue docs and a lot of other Vue tutorials, you will see that they encourage people to use $emit event rather than passing function as props (the way you are using). The docs you can read here.

https://v2.vuejs.org/v2/guide/components-custom-events.html https://v2.vuejs.org/v2/guide/components.html#Emitting-a-Value-With-an-Event https://code.tutsplus.com/tutorials/design-patterns-for-communication-between-vuejs-component--cms-32354 vue, emitting vs passing function as props

The reason is Vue philosophy is passing props down, emitting events up . Using $emit will help to mark the function triggered as a Vue event, and therefore you can use global event listener. This will also may help you to separate between data flow logic and event flow logic .

However, using function as props is not wrong, and in fact, it can be used to achieve the same result. In my preference, I use the 2nd way when I write a component that has a default function, and the function is only overridden when parents pass another one. This will help me avoid rewriting default functions many times.

For the rest of the other cases, I will use the 1st way $emit.

I did this with props.passed the parent method through props to the child component. and accessed from the child component.

in child component

props: ["lesson","fetchLessons"],

and accessed props like this in child component

this.fetchLessons();

parent component

<InstructorLesson  v-for="(lesson,index) in getFechedLessons" :lesson="lesson" :fetchLessons = "fetchLessons" v-bind:key="index"/>

Parent

<complited v-on:passData="fromChild" />

  methods: {
      fromChild(data) {
        if (data.methodCall) return this[data.methodCall]();
      }

      aFunction() {
        alert('function: a');
      }

      bFunction() {
        alert('function: b');
      }
  }

Child

<template>
   <div>
    <button @click="parentCall()">Call Parent Function
    </button>
   </div>
  </template>
  methods: {
      parentCall() {
        this.$emit("passData", {methodCall: 'aFunction' });
      }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM