如何在vue.js中从父级访问子级方法


91

我有两个嵌套的组件,从父级访问子级方法的正确方法是什么?

this.$children[0].myMethod() 似乎可以解决问题,但这很丑陋,不是吗,还有什么更好的方法:

<script>
import child from './my-child'

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>

首先,问问自己您是否真的需要。如果您的所有页面状态都在商店中(应有的状态),则无需进行父子通讯。
bbsimonbb

7
@bbsimonbb状态与事件不同。这特别是关于从父级触发子级事件。您还可以通过将prop传递到下游来执行使用Vuex的任何事情,但这需要子组件监视prop / store的更改,以便您有效地模拟RPC与数据更改,而当您想要做的一切时,这是完全错误的。触发组件中的操作。
Bojan Markovic '18年

Answers:


244

您可以使用ref

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {}
  },
  template: `
  <div>
     <ChildForm :item="item" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.$refs.form.submit()
    }
  },
  components: { ChildForm },
})

如果您不喜欢紧密耦合,则可以使用事件总线,如@Yosvel Quintero所示。下面是通过将事件总线作为道具来使用事件总线的另一个示例。

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {},
    bus: new Vue(),
  },
  template: `
  <div>
     <ChildForm :item="item" :bus="bus" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.bus.$emit('submit')
    }
  },
  components: { ChildForm },
})

组件代码。

<template>
 ...
</template>

<script>
export default {
  name: 'NowForm',
  props: ['item', 'bus'],
  methods: {
    submit() {
        ...
    }
  },
  mounted() {
    this.bus.$on('submit', this.submit)
  },  
}
</script>

https://code.luasoftware.com/tutorials/vuejs/parent-call-child-component-method/


38
这是正确的答案,实际上是阅读了实际的问题。所选答案实际上回答了相反的问题(如何从子组件中触发父方法)。
Bojan Markovic '18年

1
这个答案链接的Event Bus链接,正在重定向到State Management,在阅读@bbsimonbb注释后,这有点有意义。
Eido95

2
值得一提的是,如果使用this.$refs.,则不应动态加载子组件。
1_bug

谢谢你,先生!你救了我很多麻烦。我正在解决生产问题,并拼命寻找答案!<3
乌萨马·易卜拉欣

27

VueJS中的亲子沟通

假定所有后代都可以通过访问Vue根实例,则this.$root父组件可以通过this.$children数组访问子组件,而子组件可以通过数组访问其父组件。this.$parent,您的第一个直觉是直接访问这些组件。

VueJS文档特别针对以下两个方面提出了警告:

  • 它将父母与孩子紧密结合(反之亦然)
  • 您不能依赖父级的状态,因为它可以由子级组件修改。

解决方案是使用Vue的自定义事件界面

通过Vue实现的事件接口,您可以在组件树之间进行上下通信。利用自定义事件界面,您可以访问四种方法:

  1. $on() -允许您在Vue实例上声明一个用于监听事件的监听器
  2. $emit() -允许您在同一实例(自身)上触发事件

使用$on()和的示例$emit()

const events = new Vue({}),
    parentComponent = new Vue({
      el: '#parent',
      ready() {
        events.$on('eventGreet', () => {
          this.parentMsg = `I heard the greeting event from Child component ${++this.counter} times..`;
        });
      },
      data: {
        parentMsg: 'I am listening for an event..',
        counter: 0
      }
    }),
    childComponent = new Vue({
      el: '#child',
      methods: {
      greet: function () {
        events.$emit('eventGreet');
        this.childMsg = `I am firing greeting event ${++this.counter} times..`;
      }
    },
    data: {
      childMsg: 'I am getting ready to fire an event.',
      counter: 0
    }
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>

<div id="parent">
  <h2>Parent Component</h2>
  <p>{{parentMsg}}</p>
</div>

<div id="child">
  <h2>Child Component</h2>
  <p>{{childMsg}}</p>
  <button v-on:click="greet">Greet</button>
</div>

答案来自原始帖子:在VueJS中的组件之间进行通信


1
谢谢,所以我将尝试通过事件使我的代码相互关联!
al3x

5
复制/粘贴内容时,也要提及来源。
Mihai Vilcu '16

17
这有助于孩子与父母之间的沟通。但是,从父母到孩子,有类似的方法吗?例如,在允许用户添加新子项之前,我希望所有现有子项都得到验证-验证逻辑在子项中,因此我想遍历所有子项并执行例如validate()方法。
Mateusz Bartkowiak

66
这回答了与实际要求相反的问题。Desmond Lua的答案回答了实际问题。
Bojan Markovic '18年

4
事件总线在Chris Fritz的vue反模式列表中排名第一。可以使用事件和分布式状态进行建模的任何事物都可以使用全局状态和双向绑定进行建模,并且总的来说,您会更好。
bbsimonbb

1

当控件渲染受时,引用和事件总线都有问题v-if。因此,我决定采用一种更简单的方法。

这个想法是使用数组作为队列将需要调用的方法发送到子组件。一旦安装了组件,它将处理此队列。它监视队列以执行新方法。

(借用Desmond Lua的答案中的一些代码)

父组件代码:

import ChildComponent from './components/ChildComponent'

new Vue({
  el: '#app',
  data: {
    item: {},
    childMethodsQueue: [],
  },
  template: `
  <div>
     <ChildComponent :item="item" :methods-queue="childMethodsQueue" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.childMethodsQueue.push({name: ChildComponent.methods.save.name, params: {}})
    }
  },
  components: { ChildComponent },
})

这是ChildComponent的代码

<template>
 ...
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    methodsQueue: { type: Array },
  },
  watch: {
    methodsQueue: function () {
      this.processMethodsQueue()
    },
  },
  mounted() {
    this.processMethodsQueue()
  },
  methods: {
    save() {
        console.log("Child saved...")
    },
    processMethodsQueue() {
      if (!this.methodsQueue) return
      let len = this.methodsQueue.length
      for (let i = 0; i < len; i++) {
        let method = this.methodsQueue.shift()
        this[method.name](method.params)
      }
    },
  },
}
</script>

而且还有很多改进的余地,例如迁移processMethodsQueue到mixin ...


0

为了将一个子组件与另一个子组件进行通信,我在父对象中创建了一个方法,该方法通过以下方式在子对象中调用方法:

this.$refs.childMethod()

从另一个孩子那里,我调用了root方法:

this.$root.theRootMethod()

它为我工作。


这个答案缺乏很多解释
vsync
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.