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

al3*_*l3x 59 javascript vue.js

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

this.$children[0].myMethod() 似乎做了伎俩,但它很丑,不是吗,有什么更好的方法:

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

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

Des*_*Lua 168

你可以使用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 },
})
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢紧耦合,可以使用@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 },
})
Run Code Online (Sandbox Code Playgroud)

组件代码.

<template>
 ...
</template>

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

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

  • 这是正确的答案,实际上是阅读实际问题.所选答案实际上回答了相反的问题(如何从子组件触发父方法). (33认同)
  • 值得一提的是,如果您使用“this.$refs.”,则不应动态加载子组件。 (2认同)

wob*_*ano 47

对于Vue 2.7Vue 3.2.x

<!-- Parent -->
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './components/ChildComponent.vue'

const childComponentRef = ref()

onMounted(() => {
    childComponentRef.value.doSomething()
})
</script>

<template>
    <ChildComponent ref="childComponentRef" />
</template>
Run Code Online (Sandbox Code Playgroud)

脚本设置

<!-- Child -->
<script setup>
const doSomething = () => {
    console.log('Im batman')
}

defineExpose({
    doSomething
})
</script>
Run Code Online (Sandbox Code Playgroud)

设置功能

<!-- Child -->
<script>
import { defineComponent } from 'vue'

export default defineComponent({
    setup(props, context) {
        const doSomething = () => {
            console.log('Im batman')
        }

        context.expose({ doSomething })
    }
})
</script>
Run Code Online (Sandbox Code Playgroud)

尽可能避免这种情况并使用可组合项。除非你无法控制该组件(第三方插件等)。

来源: https: //vuejs.org/api/sfc-script-setup.html#defineexpose

  • 创建“ref”时应使用“InstanceType”。所以 `const childComponentRef = ref&lt;InstanceType&lt;typeof ChildComponent&gt;&gt;()` (3认同)
  • @sanscheese 为什么?这里或问题中没有使用打字稿。无论如何,defineExpose() 是我错过的东西。我将它放入我的子组件后立即起作用。 (3认同)
  • @dipenparmar12 这听起来像是暴露地狱。只需使用可组合项即可。 (2认同)

Yos*_*ero 24

VueJS中的亲子沟通

鉴于所有后代this.$root都可以访问根Vue实例,父组件可以通过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
    }
  });
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

从原始帖子中回答:在VueJS中的组件之间进行通信

  • 这回答了与实际问题相反的问题.Desmond Lua的回答回答了实际的问题. (54认同)
  • 这有助于从孩子到父母的沟通.但从父母到孩子有没有类似的方法呢?例如,在我允许用户添加新子项之前,我希望验证所有现有的子项 - 验证逻辑在子项中,因此我想要遍历所有这些并执行例如validate()方法. (15认同)
  • 复制/粘贴东西时,还可以提及源代码. (5认同)
  • [事件总线在Chris Fritz的vue antipatterns列表中排名第一](http://www.fullstackradio.com/87).任何可以用事件和分布式状态建模的东西都可以用全局状态和双向绑定建模,一般来说你会好得多. (3认同)

小智 8

建议的解决方案适用于 Vue 2,但如果您最终在这里寻找 Vue 3 Composition API 解决方案,您可以在迁移时执行以下操作:

模板中的子组件,具有方法 "doSomething" :

 <div class="form">                                                                                                                                                        
      <child-component ref="childComponentRef" />                                                                      
</div>  
Run Code Online (Sandbox Code Playgroud)

使用 Vue 2:

this.$refs.childComponentRef.doSomething( );
       
Run Code Online (Sandbox Code Playgroud)

使用 Vue 3 Composition Api :

    setup( )
    {
        const childComponentRef = ref( );

        childComponentRef.value.doSomething( )

        return {
           childComponentRef
        }
     }  
Run Code Online (Sandbox Code Playgroud)


moh*_*eri 5

当您的控件渲染受到 的影响时,引用和事件总线都会出现问题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 },
})
Run Code Online (Sandbox Code Playgroud)

这是 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>
Run Code Online (Sandbox Code Playgroud)

还有很大的改进空间,比如转向processMethodsQueue混合......