[英]How to update the child component b-tabs value from parent component in vuejs
I am trying to update the child component value from the parent component, when I set the value in the prop, I do get the following error,我正在尝试从父组件更新子组件值,当我在道具中设置值时,我确实收到以下错误,
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.避免直接改变 prop,因为只要父组件重新渲染,该值就会被覆盖。 Instead, use a data or computed property based on the prop's value.
相反,使用基于道具值的数据或计算属性。
I tried the below solution found on the internet but by doing so my child component prop is not getting changed when I update the parent component我尝试了在 Internet 上找到的以下解决方案,但是通过这样做,当我更新父组件时,我的子组件道具没有改变
Parent component
<template>
<child :index-val="indexVal"> </child>
</template>
<script>
export default {
props: [indexVal],
data() {
return {
indexVal: 0,
}
},
methods: {
updateVal() {
// updating value from parent
this.indexVal = 2
},
},
}
</script>
Child component
<template>
<div>
<!-- Tabs with card integration -->
<b-card no-body>
<b-tabs v-model="tabIndex" small card>
<b-tab title="tab1">tab1</b-tab>
<b-tab title="tab2">tab2</b-tab>
</b-tabs>
</b-card>
</div>
</template>
<script>
export default {
props: [indexVal],
data() {
return {
tabIndex: this.indexVal,
}
},
}
</script>
The error you're facing happens when you're trying to mutate the value of a prop
, because prop
values are coming from parents.当您尝试改变
prop
的值时会发生您面临的错误,因为prop
值来自父母。 If the parent changes it, your change inside the child will be overwritten.如果父级更改它,您在子级内部的更改将被覆盖。
Thus, when a child needs to change a prop
, it has to emit an event to the parent, update the parent value which, in turn flows the change back into the child, via the prop.因此,当孩子需要更改
prop
时,它必须向父级发出一个事件,更新父级值,然后通过 prop 将更改流回子级。
Props down , events up !
道具下来,事件起来!
To eliminate part of the boilerplate for this mechanism, Vue 2 provided the .sync
modifier .为了消除这种机制的部分样板,Vue 2 提供了
.sync
修饰符。
In Vue3, .sync
was deprecated and removed (breaking change)!在 Vue3 中,
.sync
已被弃用并删除(重大更改)!
someProp.sync
has been replaced by v-model:someProp
, because: someProp.sync
已被v-model:someProp
取代,因为:
v-model
behaviour is aligned across native form elements and Vue components.v-model
行为在原生表单元素和 Vue 组件之间保持一致。 Vue's author (Evan You), has declared over the past years that, going forward, the core team's intention is to reduce the API surface, by removing unnecessary or confusing syntax options. Vue 的作者 (Evan You) 在过去几年中宣称,未来,核心团队的意图是通过删除不必要或令人困惑的语法选项来减少 API 表面。
Vue 2 example: Vue 2 示例:
Vue.component('tab', { template: `#tab-tpl`, props: ['index', 'text'], computed: { tIndex: { get() { return this.index }, set(val) { this.$emit('update:index', val); } } } }) new Vue({ el: '#app', data: () => ({ tabs: [{text: 'one'}, {text: 'two'}, {text: 'three'}], tabIndex: 0 }), computed: { currentIndex: { get() { return this.tabIndex }, set(val) { this.tabIndex = (this.tabs.length + val) % this.tabs.length; } } } })
.tab-pills { display: flex; border-bottom: 1px solid #ccc; cursor: pointer; } .active { color: red; } .tab-pills > div { padding: .3rem .7rem; } .tab-content { padding: 1rem .7rem; } .tab-body { padding: 1rem 0 }
<script src="https://v2.vuejs.org/js/vue.min.js"></script> <div id="app"> <div class="tab-pills"> <div v-for="(tab, key) in tabs" v-text="tab.text" :class="{ active: key === currentIndex }" :key="key" @click="currentIndex = key"> </div> </div> <tab :index.sync="currentIndex" :text="tabs[currentIndex].text" class="tab-content"></tab> </div> <template id="tab-tpl"> <div> <div v-text="text" class="tab-body"></div> <button @click="tIndex -= 1">Prev</button> <button @click="tIndex += 1">Next</button> </div> </template>
Same thing, in Vue 3 (Composition API):同样的事情,在 Vue 3(组合 API)中:
const { defineComponent, toRefs, reactive, computed, createApp } = Vue; const Tab = defineComponent({ template: '#tab-tpl', props: ['index', 'text'], setup: (props, { emit }) => ({ tIndex: computed({ get: () => props.index, set: val => emit('update:index', val) }) }) }); const Tabs = defineComponent({ template: '#tabs-tpl', components: { Tab }, setup() { const state = reactive({ tabs: ['one', 'two', 'three'].map(text => ({ text })), tabIndex: 0, currentIndex: computed({ get: () => state.tabIndex, set: val => state.tabIndex = (state.tabs.length + val) % state.tabs.length }) }) return {...toRefs(state)} } }); createApp(Tabs).mount('#app')
.tab-pills { display: flex; border-bottom: 1px solid #ccc; cursor: pointer; } .active { color: red; } .tab-pills > div { padding: .3rem .7rem; } .tab-content { padding: 1rem .7rem; } .tab-body { padding: 1rem 0 }
<script src="https://unpkg.com/vue@3.2/dist/vue.global.prod.js"></script> <div id="app"></div> <template id="tabs-tpl"> <div class="tab-pills"> <div v-for="(tab, key) in tabs" v-text="tab.text" :class="{ active: key === currentIndex }" :key="key" @click="currentIndex = key"> </div> </div> <tab v-model:index="currentIndex" :text="tabs[currentIndex].text" class="tab-content"></tab> </template> <template id="tab-tpl"> <div v-text="text" class="tab-body"></div> <button @click="tIndex -= 1">Prev</button> <button @click="tIndex += 1">Next</button> </template>
In both examples, the tab controls at the top change tabIndex
at parent level .在这两个示例中,顶部的选项卡控件更改了父级别的
tabIndex
。
The buttons inside the tab, change it from the child (by emitting the updated value to parent).选项卡内的按钮,从子级更改它(通过将更新的值发送给父级)。
The important part is that tabIndex
changes in parent component, which drives the update in the child.重要的部分是父组件中的
tabIndex
更改,它驱动子组件中的更新。 Don't mind the currentIndex
computed in parent, that's just an implementation detail (it allows going to first tab when clicking Next
on last tab and going to last when hitting Prev
on first tab - that's the only reason why I added it, it's not necessary for all of this to work).不要介意在父项中计算的
currentIndex
,这只是一个实现细节(它允许在最后一个选项卡上单击Next
时进入第一个选项卡,并在第一个选项卡上单击Prev
时进入最后一个选项卡 - 这是我添加它的唯一原因,它不是所有这些工作都需要)。
If something is unclear, check the doc links I posted above, for the Vue version you're using.如果有不清楚的地方,请查看我在上面发布的文档链接,了解您正在使用的 Vue 版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.