如何使用 Vue.js 在父组件中更新子组件中的数据?
Posted
技术标签:
【中文标题】如何使用 Vue.js 在父组件中更新子组件中的数据?【英文标题】:How can I use data in the child component that are updated in parent component using Vue.js? 【发布时间】:2019-02-19 09:02:46 【问题描述】:我的父组件如下所示:
<template>
...
<PaymentMethod/>
...
<b-btn class="float-right" variant="primary" @click="add">
OK
</b-btn>
...
</template>
<script>
export default
...
methods:
add()
...
</script>
我的子组件看起来像:
<template>
...
<b-form-select v-model="selected" :options="methodOptions" />
...
<b-form-select v-model="termSelected" :options="termOptions" />
...
</template>
<script>
export default
data ()
return
selected: null,
termSelected: null
,
...
</script>
如果从父组件调用add
方法,我希望它获取子组件中选择的数据
我该怎么做?
【问题讨论】:
你发出来,vuejs.org/v2/guide/components.html 【参考方案1】:一种解决方案是使用 sync
修饰符以及计算的 getter 和 setter:
父组件
<template>
...
<PaymentMethod :method.sync="method" :term.sync="term"/>
...
<b-btn class="float-right" variant="primary" @click="add">
OK
</b-btn>
...
</template>
<script>
export default
data ()
return
method: null,
term: null
,
...
</script>
子组件
<template>
...
<b-form-select v-model="_method" :options="methodOptions" />
...
<b-form-select v-model="_term" :options="termOptions" />
...
</template>
<script>
export default
props: ['method', 'term'],
computed:
_method:
get ()
return this.method
,
set (value)
this.$emit('update:method', value)
,
_term:
get ()
return this.term
,
set (value)
this.$emit('update:term', value)
,
,
...
</script>
现在使用父组件的 add
方法,您可以访问子组件的选定 method
和 term
选项:
methods:
add()
// this.method is the value of _method
// this.term is the value of _term
更新
由于您已声明您需要所选术语/方法的值和文本,我建议进行以下更改:
家长
<template>
...
<PaymentMethod :methods="methods"
:terms="terms"
:method.sync="method"
:term.sync="term"/>
...
<b-btn class="float-right" variant="primary" @click="add">
OK
</b-btn>
...
</template>
<script>
export default
data ()
return
// define your method and term arrays in the parent component.
// pass them as props to the child component.
methods: [..., ..., ...],
terms: [..., ..., ...],
method: null,
term: null
,
// use computed properties to retrieve the selected method / term option.
computed:
selectedMethod ()
return this.methods.find(method => method.value === this.method)
,
selectedTerm ()
return this.terms.find(term => term.value === this.term)
,
...
</script>
儿童
<template>
...
<b-form-select v-model="_method" :options="methods" />
...
<b-form-select v-model="_term" :options="terms" />
...
</template>
<script>
export default
props: ['method', 'term', 'methods', 'terms'],
computed:
_method:
get ()
return this.method
,
set (value)
this.$emit('update:method', value)
,
_term:
get ()
return this.term
,
set (value)
this.$emit('update:term', value)
,
,
...
</script>
【讨论】:
太棒了。但仍有不足之处。此代码:this.$emit('term', value)
。应该this.$emit('update:term', value)
我可以从每个选项中获取文本吗?如果我使用你的方式,我只会得到每个选项的价值。我也想收文
你怎么看?
为此,您需要执行以下操作:1) 使用所选对象触发事件 - this.$emit('selected-term', this.terms.find(term => term.value === value))
- 而不是 this.$emit('update:term', value)
,然后手动更新父组件中的道具,或者 2 ),将方法和术语也作为道具传递给子组件,当更新事件触发时,在父组件中搜索相应的术语/方法,如第一个示例所示。两者都相似,但#2 更容易实现,IMO。 Vuex/shared state 也是一个不错的选择。
我尝试更新答案并更改父组件中的数据,如下所示:methods: [], terms: []
。在selectedMethod
计算中,我添加console.log(this.methods)
。然后我尝试选择方法。没有结果【参考方案2】:
使用 Vuex,您的 store.js 将如下所示:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state =
selected: null
;
const mutations =
SET_SELECTED(state, selected)
state.selected =selected;
export default new Vuex.Store(
state,
mutations
)
在 app.js 中:
import store from './vuex/store';
const app = new Vue(
el: '#app',
store,
...)
在父组件中:
<template>
...
<PaymentMethod :selected="selected" />
...
<b-btn class="float-right" variant="primary" @click="add">
OK
</b-btn>
...
</template>
<script>
export default
data()
returen
selected:null
,
methods:
add()
...
this.$store.commit("SET_SELECTED",this.selected)
</script>
在子组件中:
<template>
...
<b-form-select @change="selectItem" v-model="selected"
:options="methodOptions" />
...
</template>
<script>
export default
data ()
return
selected:null
,
methods:
selectItem()
this.$store.commit("SET_SELECTED",this.selected
...
【讨论】:
存在错误:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "selected"
是的,您可以将v-model
绑定到数据对象中名为selectedProp
的属性
但是有了你的解决方案,他仍然无法更改子组件中的this.selected
。当你使用v-model
时,你应该实现getter 和setter。
@boussadjra brahim,它不起作用。如果我在add方法中console.log(this.selectedInParent)
,结果是null
@boussadjra brahim 似乎可行。但是如果我有 2 个选择呢?试着看看我的问题。我已经更新了【参考方案3】:
最好和推荐的方法是使用 $emit 下面的例子可以告诉你怎么做?
Vue.component('child-tmp',
props: ['post'],
template: `
<button @click="$emit('add-like')">Like</button>
`
)
new Vue(
el: "#app",
data:
posts: [
title: "Heading goes here 1",
content: "Something sadofnd idfidif disong.",
likes: 0
,
title: "Heading 2 goes here",
content: "Something sadofnd idfidif disong.",
likes: 0
],
totalLikes: 0
)
<script src="https://unpkg.com/vue"></script>
<div id="app">
<h2>Posts:</h2>
<section>
<div v-for="post in posts">
<h2>
post.title
</h2>
<p>
post.content
</p>
<child-tmp v-bind:post="post" v-on:add-like="post.likes = post.likes+1"></child-tmp><span style="margin-left:10px;">post.likes</span>
</div>
</section>
</div>
在上面的 sn-p 中,您可以看到我们正在使用 props 从父级到子级读取数据,我们使用 $emit 从子级传递数据,并使用 v-on:add-like 接收发出的数据。
【讨论】:
【参考方案4】:有两种方式:
1.您可以在子组件中选择数据时发出事件:
<template>
...
<b-form-select v-model="selected" :options="methodOptions" />
...
</template>
<script>
export default
data ()
return
selected: null
,
...
methods:
onSelect()
this.$emit('selectData', this.selected);
</script>
然后在父组件中处理这个事件:
<template>
...
<PaymentMethod @selectData="changeChildData($event)"/>
...
<b-btn class="float-right" variant="primary" @click="add">
OK
</b-btn>
...
</template>
<script>
export default
...
data()
return
childData: null
,
methods:
changeChildData(newData)
this.childData = newData;
,
add()
...
</script>
2。或者你可以使用存储Vuex
或事件总线(Vuex 的简化版):
import Vue from 'vue';
export const EventBus = new Vue();
您将数据从子级传递到事件总线
<script>
import EventBus from '../EventBus.js';
export default
data ()
return
selected: null
,
...
methods:
onSelect()
EventBus.$emit('selectData', this.selected);
</script>
并从父母那里订阅它的变化
<script>
import EventBus from '../EventBus.js';
export default
...
data()
return
childData: null
,
created()
EventBus.$on('selectData', (data) =>
this.childData = data;
);
,
methods:
add()
...
</script>
【讨论】:
你的第一种方法是行不通的。如果我在onSelect
方法中console.log('test')
并选择了该选项,则没有结果
@SuccessMan 不理解与console.log()
的联系。它不会以任何方式影响代码。我从我的工作代码中获取了这个片段。也许有些错别字,但它对我有用。
@SuccessMan 我修改了父代码,引入了新方法。尝试测试这个变量并确保调用了 changeChildData
方法。
您的第一个示例正是 sync 修饰符的用途。将 Vuex 等同于事件总线过于简单化,并且忽略了反应状态系统的要点。
@DigitalDrifter 不知道sync
。好像是个新功能。谢谢!以上是关于如何使用 Vue.js 在父组件中更新子组件中的数据?的主要内容,如果未能解决你的问题,请参考以下文章