我正在使用 webpack 的 vue-cli 脚手架
我的 Vue 组件结构/层次结构当前如下所示:
在应用程序级别,我想要一个 vuejs 组件方法,可以将所有子组件的数据聚合到一个可以发送到服务器的 JSON 对象中。
有没有办法访问子组件的数据?具体来说,多层深?
如果不是,传递可观察数据/参数的最佳实践是什么,以便当子组件修改它时我可以访问新值?我试图避免组件之间的硬依赖关系,因此到目前为止,使用组件属性传递的唯一内容是初始化值。
更新:
可靠的答案。查看这两个答案后我发现有用的资源:
在某些情况下,家长可以使用引用直接访问孩子的数据。
例如
<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。
对于这种结构最好有某种 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,这就是您可以使用的基本流程。
传递可观察数据/参数的最佳实践是什么,以便当子组件修改它时我可以访问新值?
道具的流动是单向的,孩子不应该直接修改其道具。
对于复杂的应用程序,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)
您可以引用子组件并将其用作此组件 this.$refs.refComponentName.$data
父组件
<template>
<section>
<childComponent ref="nameOfRef" />
</section>
</template>
methods: {
save() {
let Data = this.$refs.nameOfRef.$data;
}
},
就我而言,我有一个注册表单,我已将其分解为多个组件。
正如上面所建议的,我使用了 $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
}
}
这很有效,因为数据是反应性的。
没有人提到 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 />
框中输入消息时,祖父母将反映该消息。