使用组件调用父级方法

100

我有一个组件,想要在Vue中为其添加一个点击监听器,并运行父模板中的一个方法。这是否可行?

<template>
    <custom-element @click="someMethod"></custom-element>
</template>

<script>
    export default {
        name: 'template',
        methods: {
            someMethod: function() {
                console.log(true);
        }
    }
</script>

1
在您发布的代码中,当单击custom-element时,将运行someMethod。这是您想要的吗,还是有其他场景? - Bert
1
可能是Vue.js继承调用父方法的重复问题。 - thanksd
7个回答

177

是的!

在Vue组件中,可以通过调用$parent属性来从子组件中调用父组件的方法,非常简单。

这里有一个演示如何实现这一功能的JSFiddle:https://jsfiddle.net/50qt9ce3/1/

<script src="https://unpkg.com/vue"></script>

<template id="child-template">
    <span @click="someMethod">Click me!</span>
</template>

<div id="app">
  <child></child>
</div>

<script>
Vue.component('child', {
  template: '#child-template',
  methods: {
    someMethod(){
        this.$parent.someMethod();
    }
    }
});

var app = new Vue({
    el: '#app',
  methods: {
    someMethod(){
        alert('parent');
    }
    }
});
</script>

注意: 尽管在构建不连通的可重用组件时不推荐这样做,但有时候我们正在构建相关的非可重用组件,在这种情况下非常方便。


11
这个对我不再起作用,出现了 this.$parent.myMethod 不是一个函数 的错误。 - raklos
2
@raklos,它仍然可以在最新版本的vue.js上运行,目前是2.6.11。如果它对你不起作用,问题就在其他地方。我建议您提出另一个带有您正在使用的代码的问题以获得帮助。 - Gudradain
10
如果出现“this.$parent.myMethod不是一个函数”的错误,请尝试使用this.$parent.$parent.myMethod或者this.$parent.$parent.$parent.myMethod等方法。可能会出现您的方法不在直接父组件中,而是在更高层次的组件层级中的情况。请注意不要改变原意。 - Ilyich
2
这个解决方案非常不可靠,因为它依赖于组件层次结构。如果您从模板内的不同组件中调用该方法,则它将无法正常工作:`<template id="child-template"> 点击我! 点击我! </template>` - migli
1
提供/注入和props/emit是用户代码的好工具,但在开发库时,您可能不希望通过向任意后代提供数据来污染您的API,也不希望让消费者执行样板事件绑定。当部署更合适的声明性语言时,直接与其父组件通信的组件只是反模式 - 有时候闻起来不好的代码会尝起来很好。话虽如此,$parent.$parent是一个必须认真考虑的罪恶诱惑。 - Isabelle Wedin
显示剩余3条评论

58

直接来自Vue.js documentation

在Vue中,父子组件关系可以概括为props向下传递,事件向上传递。父组件通过props向子组件传递数据,而子组件通过事件向父组件发送消息...

因此,当子组件发生某些事情时,您需要从子组件发出一个click事件,这个事件可以用来调用父模板中的方法。

如果您不想从子组件显式地发出事件(使用this.$emit('click')从子组件中),您还可以尝试使用native click event@click.native="someMethod"


38

依赖于调用this.$parent会隐藏依赖项,并且在使用创建更长子层次结构的组件库时会中断。

首选方法是:

  1. 明确地将方法作为属性传递给子组件(与传递数据道具相同)
  2. 或者将全局方法声明为混合

来自nils关于Vue.js inheritance call parent method的答案:

  1. Passing props (parent-child)

    var SomeComponentA = Vue.extend({
        methods: {
            someFunction: function () {
                // ClassA some stuff
            }
        }
    });
    
    var SomeComponentB = Vue.extend({
       props: [ 'someFunctionParent' ],
       methods: {
           someFunction: function () {
               // Do your stuff
               this.someFunctionParent();
           }
       }
    });
    

    and in the template of SomeComponentA:

    <some-component-b :someFunctionParent="someFunction"></some-component-b>
    
  2. Use Mixins

    If this is common functionality that you want to use in other places, using a mixin might be more idiomatic:

    var mixin = {
        methods: {
            someFunction: function() {
                // ...
            }
        }
    };
    var SomeComponentA = Vue.extend({
        mixins: [ mixin ],
        methods: {
        }
    });
    
    var SomeComponentB = Vue.extend({
       methods: {
           someFunctionExtended: function () {
               // Do your stuff
               this.someFunction();
           }
       }
    });
    

进一步阅读


第一种方法是我个人认为非常好的。是我见过最好的。实现这个功能,我本来会用Vuex的,但由于要启用模态框,这需要付出大量的工作。 - errata

8
你可以通过 props 将父级方法传递到子组件中,或者让子组件发出自定义或原生事件。

这里有一个Plunker演示了这两种方法。


6

您可以在纯Vue中使用$root像这样,但是,如果您在Vue中使用nuxt,那么该响应将不起作用。为什么?因为$root就是nuxt本身。让我给您举个例子:

this.$root.$children[1].myRootMethod()
  • $root: 正如我之前所说,这是nuxt。

  • $children[0]: 这是nuxtloading。

  • $children[1]: 这是您的主组件,在我的情况下,它是一个基本布局,具有一些全局组件和全局mixin。

  • $children[n]: 应用程序中的其他组件。

希望能帮到您。


这个代码可以运行,但是有点反模式。它会降低可读性。对于类似的情况(反模式),更好的方法是访问$parent来调用该方法。this.$parent.parentMethod() - Chase Choi
@ChaseChoi 不行,因为我的代码就像绝对路径一样,它不依赖于子组件,因为结果总是相同的。 - mrroot5
this.$parent.$options.methods.methodName(); 对我来说是唯一有效的... - 3xCh1_23
是的,如果您只有一个父组件而不是曾祖父或未知数量的父组件,则可以使用此方法。 - mrroot5

6
在当前的Vue版本中,这个解决方案是:
传递属性(父子组件)
var SomeComponentA = Vue.extend({
    methods: {
        someFunction: function () {
            // ClassA some stuff
        }
    }
});

var SomeComponentB = Vue.extend({
   props: [ 'someFunctionParent' ],
   methods: {
       someFunction: function () {
           // Do your stuff
           this.someFunctionParent();
       }
   }
});

HTML部分:

<some-component-b someFunctionParent="someFunction"></some-component-b>

基于这篇文章,应该按照以下方式进行修改:

<some-component-b v-bind:someFunctionParent="someFunction"></some-component-b>

3

Vue 3的解决方案:

提供一个函数给子组件的另一种方式是使用provide/inject。其优点在于,您可以避免通过多个组件传递props,因为inject可以在任何深度的子组件中使用。

父组件:

<script setup>

import { provide } from 'vue'

myFunction(){
console.log('message from parent');
}

provide('message', myFunction);

一些子组件:

<script setup>
import { inject } from 'vue'

const msg = inject('message')

//calling the injected function
msg()

</script>

查看文档.


在下面的示例中,如何使用provide()和传递"someMethod"来实现呢?export default { methods: { someMethod } } - Derek
在这个链接(https://vuejs.org/guide/components/provide-inject.html)上,你可以点击左上角的Options来查看Options API的示例。 - Stefan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接