简体   繁体   English

如何从 vuejs 中的父组件更新子组件 b-tabs 值

[英]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取代,因为:

  • they were providing the same functionality (dual binding),它们提供相同的功能(双重绑定),
  • this increased the confusion between the two syntaxes and their particular implementation details.这增加了两种语法及其特定实现细节之间的混淆。
  • now 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM