[英]How to update the child component b-tabs value from parent component in vuejs
我正在嘗試從父組件更新子組件值,當我在道具中設置值時,我確實收到以下錯誤,
避免直接改變 prop,因為只要父組件重新渲染,該值就會被覆蓋。 相反,使用基於道具值的數據或計算屬性。
我嘗試了在 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>
當您嘗試改變prop
的值時會發生您面臨的錯誤,因為prop
值來自父母。 如果父級更改它,您在子級內部的更改將被覆蓋。
因此,當孩子需要更改prop
時,它必須向父級發出一個事件,更新父級值,然后通過 prop 將更改流回子級。
道具下來,事件起來!
為了消除這種機制的部分樣板,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/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>
在這兩個示例中,頂部的選項卡控件更改了父級別的tabIndex
。
選項卡內的按鈕,從子級更改它(通過將更新的值發送給父級)。
重要的部分是父組件中的tabIndex
更改,它驅動子組件中的更新。 不要介意在父項中計算的currentIndex
,這只是一個實現細節(它允許在最后一個選項卡上單擊Next
時進入第一個選項卡,並在第一個選項卡上單擊Prev
時進入最后一個選項卡 - 這是我添加它的唯一原因,它不是所有這些工作都需要)。
如果有不清楚的地方,請查看我在上面發布的文檔鏈接,了解您正在使用的 Vue 版本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.