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

发布于 2025-02-11 01:52:05 字数 1228 浏览 1 评论 0原文

我正在尝试从父组件中更新子组件值,当我在道具中设置值时,我确实会收到以下错误,

避免直接突变道具,因为每当parent the parent consement re-the the值都会被覆盖渲染。取而代之的是,根据道具的值使用数据或计算属性。

我尝试了以下解决方案在Internet上找到的解决方案,但是当我更新parent parent copement

parent parent 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>

<代码>儿童组件

<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>

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. 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

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

总攻大人 2025-02-18 01:52:05

当您试图突变prop的值时,您面临的错误会发生,因为prop值来自父母。如果父母更改它,则您的内部更改将被覆盖。

因此,当孩子需要更改prop时,它必须向父母发出事件,请更新父值,而父母值又通过道具将更改返回到孩子。

props down ,事件 up

为了消除该机构的一部分样板,VUE 2提供了 .sync修饰符

在vue3中,.sync被弃用并删除(打破更改)!
someprop.sync 已被替换 V-Model:SomeProp,因为:

  • 他们提供了相同的功能(双重绑定),
  • 这增加了两个语法之间的混淆及其特定的实现详细信息。
  • 现在,V-Model行为在本机形式元素和VUE组件之间对齐。

Vue的作者(Evan You)在过去几年中宣布,未来,核心团队的目的是通过消除不必要或混淆语法选项来减少API表面。


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>

同样的事情,在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/[email protected]/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>


在这两个示例中,TAB在 parth parth级别 at top Change> TabIndex 均在Top Change 上进行控件。

选项卡中的按钮,将其从子(通过将更新值散布到父)将其更改。

重要的部分是tabindex父母组件中的更改,它可以驱动孩子的更新。不要介意在父级中计算的currentIndex,这只是一个实现细节(在最后一个选项卡上单击下一个时,它允许第一个选项卡> prev 在第一个选项卡上 - 这是我添加它的唯一原因,所有这些都没有必要使用)。

如果不清楚,请查看您正在使用的VUE版本上面发布的文档链接。

The error you're facing happens when you're trying to mutate the value of a prop, because prop values are coming from parents. 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.

Props down, events up!

To eliminate part of the boilerplate for this mechanism, Vue 2 provided the .sync modifier.

In Vue3, .sync was deprecated and removed (breaking change)!
someProp.sync has been replaced by v-model:someProp, because:

  • 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.

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 2 example:

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):

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/[email protected]/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.

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. 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).

If something is unclear, check the doc links I posted above, for the Vue version you're using.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文