這章節是延伸v-if和v-show管理元件,如何用更簡便的方式做tab頁籤。
做一個tab
按鈕切會下面顯示的內容,直覺的方式是直接用v-if
去寫三個元件
<button v-for="tab in tabs"
:key="tab"
@click="currentTab = tab"
:class="{'active': currentTab === tab}">
{{tab}}
</button>
<tab-a v-if="currentTab === 'A'"></tab-a>
<tab-b v-if="currentTab === 'B'"></tab-b>
<tab-c v-if="currentTab === 'C'"></tab-c>
const app = Vue.createApp({
data() {
return {
currentTab: 'A',
tabs: ['A', 'B', 'C']
}
}
});
app.component('tab-a', {
template: `
<h1>aaaaaaaaaaaaaaaaaa</h1>
`
})
app.component('tab-b', {
template: `
<h1>bbbbbbbbbbbbbbbbbb</h1>
`
})
app.component('tab-c', {
template: `
<h1>ccccccccccccccccc</h1>
`
})
用更快的方式就是使用v-bind:is
,新增一個computed
,當點擊按鈕時會觸發currentTab = tab
,此時新的tab
就會傳到:is="currentTabComponent"
身上,即顯示出與用v-if
一樣的結果。
<button v-for="tab in tabs"
:key="tab"
@click="currentTab = tab"
:class="{'active': currentTab === tab}">
{{tab}}
</button>
<component :is="currentTabComponent"></component>
const app = Vue.createApp({
data() {
return {
currentTab: 'A',
tabs: ['A', 'B', 'C']
}
},
computed: {
currentTabComponent() {
return `tab-${this.currentTab.toLowerCase()}`;
}
}
});
app.component('tab-a', {
template: `<h1>aaaaaaaaaaaaaaaaaa</h1>`
})
app.component('tab-b', {
template: `<h1>bbbbbbbbbbbbbbbbbb</h1>`
})
app.component('tab-c', {
template: `<h1>ccccccccccccccccc</h1>`
})
改寫剛剛的tab頁籤,內容物改成v-model
綁定的input
可以改寫資料。
改寫資料後按下其它標籤會發先先前改寫的資料會被還原成初始值。
app.component('tab-a', {
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'A component' })
})
app.component('tab-b', {
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'B component' })
})
app.component('tab-c', {
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'C component' })
})
若想讓資料在切換時也能保持改寫後的樣子,就可以在外層包上keep-alive
。
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
補充: keep-alive
同一時間只會有一個子元件被渲染
使用時必須搭配name
屬性
<!-- 寫法一:逗點格開 -->
<keep-alive include="A-TAB,B-TAB">
<component :is="currentTabComponent"></component>
</keep-alive>
<!-- 寫法二:Regular expression -->
<keep-alive :include="/(A|B)-TAB/">
<component :is="currentTabComponent"></component>
</keep-alive>
<!-- 寫法三:陣列 -->
<keep-alive :include="['A-TAB','B-TAB']">
<component :is="currentTabComponent"></component>
</keep-alive>
app.component('tab-a', {
name: 'A-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'A component' })
})
app.component('tab-b', {
name: 'B-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'B component' })
})
app.component('tab-c', {
name: 'C-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'C component' })
})
只保留最後引入的兩個狀態
<keep-alive :max="2">
<component :is="currentTabComponent"></component>
</keep-alive>
生命週期中activated
與deactivated
兩個hooks是給keep-alive使用的。
直接比對有和無keep-alive的差異在生命週期上有什麼不同。
做了同樣的動作: 點擊A標籤→B標籤→C標籤
有keep-alive
切換時的順序為「建立新元件created」→「暫停目前元件 deactivated」→「掛載新的元件 mounted」→「啟用新的元件 activated」
無keep-alive
切換時的順序為「建立新元件created」→「銷毀目前元件 unmounted」→「掛載新的元件 mounted」
const app = Vue.createApp({
data() {
return {
currentTab: 'A',
tabs: ['A', 'B', 'C'],
msgs: []
}
},
computed: {
currentTabComponent() {
return `tab-${this.currentTab.toLowerCase()}`;
}
},
methods: {
notify(val) {
this.msgs.push(val)
}
},
});
app.component('tab-a', {
name: 'A-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'A component' }),
created() {
this.$emit('update', `${this.$options.name} Created`)
},
mounted() {
this.$emit('update', `${this.$options.name} Mounted`)
},
unmounted() {
this.$emit('update', `${this.$options.name} Unmounted`)
},
activated() {
this.$emit('update', `${this.$options.name} Activated`)
},
deactivated() {
this.$emit('update', `${this.$options.name} Deactivated`)
}
})
app.component('tab-b', {
name: 'B-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'B component' }),
created() {
this.$emit('update', `${this.$options.name} Created`)
},
mounted() {
this.$emit('update', `${this.$options.name} Mounted`)
},
unmounted() {
this.$emit('update', `${this.$options.name} Unmounted`)
},
activated() {
this.$emit('update', `${this.$options.name} Activated`)
},
deactivated() {
this.$emit('update', `${this.$options.name} Deactivated`)
}
})
app.component('tab-c', {
name: 'C-TAB',
template: `<input type="text" v-model="title">`,
data: () => ({ title: 'C component' }),
created() {
this.$emit('update', `${this.$options.name} Created`)
},
mounted() {
this.$emit('update', `${this.$options.name} Mounted`)
},
unmounted() {
this.$emit('update', `${this.$options.name} Unmounted`)
},
activated() {
this.$emit('update', `${this.$options.name} Activated`)
},
deactivated() {
this.$emit('update', `${this.$options.name} Deactivated`)
}
})