VueJS 从父组件访问子组件的数据

问题描述 投票:0回答:6

我正在使用 webpack 的 vue-cli 脚手架

我的 Vue 组件结构/层次结构当前如下所示:

  • 应用程序
    • PDF模板
      • 背景
      • 动态模板图像
      • 静态模板图像
      • 降价

在应用程序级别,我想要一个 vuejs 组件方法,可以将所有子组件的数据聚合到一个可以发送到服务器的 JSON 对象中。

有没有办法访问子组件的数据?具体来说,多层深?

如果不是,传递可观察数据/参数的最佳实践是什么,以便当子组件修改它时我可以访问新值?我试图避免组件之间的硬依赖关系,因此到目前为止,使用组件属性传递的唯一内容是初始化值。

更新:

可靠的答案。查看这两个答案后我发现有用的资源:

vue.js vue-component vuex
6个回答
91
投票

在某些情况下,家长可以使用引用直接访问孩子的数据。

例如

<markdown ref="markdowndetails"></markdown>
<app-button @submit="process"></app-button>

// js
methods:{
    process: function(){
        // items is a defined object inside data()
        var markdowns = this.$refs.markdowndetails.items 
    }
}

对于复杂的状态管理场景,有效的方法是使用Vuex。


60
投票

对于这种结构最好有某种 Store。

VueJS 为此提供了解决方案,它被称为 Vuex。如果你还没有准备好使用 Vuex,你可以创建自己的简单商店。

让我们试试这个

MarkdownStore.js

export default {

 data: {
   items: []
 },

 // Methods that you need, for e.g fetching data from server etc.

 fetchData() {
   // fetch logic
 }

}

现在您可以通过导入此商店文件在任何地方使用这些数据

HomeView.vue

import MarkdownStore from '../stores/MarkdownStore'

export default {

 data() {
   sharedItems: MarkdownStore.data
 },

 created() {
   MarkdownStore.fetchData()
 }

}

如果您不想使用 Vuex,这就是您可以使用的基本流程。


35
投票

传递可观察数据/参数的最佳实践是什么,以便当子组件修改它时我可以访问新值?

道具的流动是单向的,孩子不应该直接修改其道具。

对于复杂的应用程序,vuex 是解决方案,但对于简单的情况,vuex 就有点大材小用了。就像 @Belmin 所说的那样,由于反应性系统,您甚至可以使用普通的 JavaScript 对象来实现这一点。

另一个解决方案是使用事件。 Vue 已经实现了 EventEmitter 接口,子级可以使用

this.$emit('eventName', data)
与父级进行通信。

家长将像这样监听该事件:(

@update
v-on:update
的简写)

<child :value="value" @update="onChildUpdate" />

并更新事件处理程序中的数据:

methods: {
  onChildUpdate (newValue) {
    this.value = newValue
  }
}

这是 Vue 中自定义事件的简单示例:
http://codepen.io/CodinCat/pen/ZBELjm?editors=1010

这只是父子通信,如果一个组件需要与它的兄弟组件通信,那么你将需要一个全局事件总线,在Vue.js中,你可以只使用一个空的Vue实例:

const bus = new Vue()

// In component A
bus.$on('somethingUpdated', data => { ... })

// In component B
bus.$emit('somethingUpdated', newData)

17
投票

您可以引用子组件并将其用作此组件 this.$refs.refComponentName.$data

父组件

<template>
   <section>
      <childComponent ref="nameOfRef" />
   </section>
</template>

 methods: {
  save() {
   let Data = this.$refs.nameOfRef.$data;
 }
},

5
投票

就我而言,我有一个注册表单,我已将其分解为多个组件。

正如上面所建议的,我使用了 $refs,在我的父母中,我有例如:

在模板中:

<Personal ref="personal" />

脚本 - 父组件

export default {
  components: {
    Personal,
    Employment
  },
  data() {
    return {
        personal: null,
        education: null
    }
  },
  mounted: function(){
       this.personal = this.$refs.personal.model
       this.education = this.$refs.education.model
  }
}

这很有效,因为数据是反应性的。


0
投票

没有人提到 Provide/Inject 的使用。我并不是说这是最好的方法,但它是创建简单的祖父母/孙子反应性的“一种”方法,而不必担心数据存储的复杂性。

与往常一样,以下解决方案附带健康警告。仅在您知道孙子将永远是祖父的后代的小型简化应用程序上使用它!巴拉巴拉......

(顺便说一句,这可以在 Vue3 中使用 Composition API 运行。)

// Grandparent component
<script setup>
import { ref, provide } from 'vue'
import Child from './Child.vue'

const message = ref('hello')

function changeMessage(e) {
    message.value = e.target.value;
}

provide('message', { message, changeMessage});
</script>

<template>
    <p>The value from the grandchild is: {{ message }}</p>
    <Child />
</template>

在我的简单示例中,子组件除了证明反应性逻辑可以通过它之外什么也不做:

// file: Child.vue
<script setup>
import GrandChild from './GrandChild.vue'
</script>
<template>
    <GrandChild />
</template>

孙子长这个样子:

// file: GrandChild.vue
<script setup>
import { inject } from 'vue'
const { message, changeMessage } = inject('message');
</script>

<template>
    <p>
        Message to send grandparent: <input :value="message" @input="changeMessage" />
    </p>
</template>

当您在孙子的

<input />
框中输入消息时,祖父母将反映该消息。

文档: https://vuejs.org/guide/components/provide-inject.html

© www.soinside.com 2019 - 2024. All rights reserved.