當在 Vue.js 中使用 <keep-alive>
組件時,它將會緩存動態(tài)組件,而不是每次渲染都銷毀和重新創(chuàng)建它們。這對于需要在組件間快速切換并且保持組件狀態(tài)的情況非常有用。
<keep-alive>
只能包含(或者說只能渲染)一個子組件,如果需要包含多個子組件,需要用 v-if
選擇某個確定的組件進行渲染。也可以使用 <template>
或其他組件標簽將它們包裹起來,再通過 v-if
選擇確定的某個組件進行渲染。因此 keep-alive
標簽里面有且只有一個子節(jié)點(或者說只能渲染一個子節(jié)點)。這些子組件可以通過動態(tài)組件或者其他方式進行切換。
當一個被 <keep-alive>
組件包裹的組件被切換出去時,它的狀態(tài)將會被保留在內(nèi)存中,而不會被銷毀。當組件再次被切換回來時,它會從緩存中直接取出,并且保持之前的狀態(tài)。
1. keep-alive 和 v-show 的區(qū)別
- 作用:
<keep-alive>
:用于緩存組件,以避免每次組件切換時銷毀和重新創(chuàng)建實例。它會保留組件的狀態(tài),以便在需要時直接從緩存中取出。
v-show
:用于根據(jù)條件動態(tài)顯示或隱藏組件。它通過控制 display CSS 屬性來決定組件是否在 DOM 中渲染。
- 使用場景:
<keep-alive>
:適用于需要在組件間快速切換并保持組件狀態(tài)的場景。例如,當你有一個包含表單的編輯頁面,在切換到其他頁面并返回時,希望保留用戶已輸入的數(shù)據(jù)。
v-show
:適用于根據(jù)某些條件動態(tài)顯示或隱藏單個組件。例如,根據(jù)用戶權(quán)限動態(tài)顯示不同的導航菜單。
- 對組件實例的影響:
<keep-alive>
:保留組件的狀態(tài)和實例,只是保存虛擬 DOM ,以便在需要時直接從緩存中取出。組件的生命周期鉤子函數(shù) activated 和 deactivated 也會在緩存和激活時觸發(fā)。
v-show
:每次切換顯示或隱藏時,組件實例會保持不變,存在于真實 DOM ,并且會觸發(fā)相應(yīng)的生命周期鉤子函數(shù) beforeUpdate 和 updated。
2. keep-alive 使用案例
App.vue
<template>
<el-button type="primary" @click="flag = !flag"> 切換組件</el-button>
<!-- [] 里面名稱是原本的組件名 -->
<!--
props介紹:
:exclude="['A']" 不緩存A組件
:include="['A']" 緩存A組件
:max="2" 最多緩存2個,如有多個從后往前算起
-->
<keep-alive :exclude="['A']">
<AVue v-if="flag"></AVue>
<B v-else></B>
</keep-alive>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import AVue from './components/A.vue'
import B from './components/B.vue'
const flag = ref<boolean>(true)
</script>
<style scoped></style>
A.vue
<template>
<h1 style="margin: 10px;">我是A組件</h1>
<el-form :model="form" label-width="120px">
<el-form-item label="Activity name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="Activity zone">
<el-select v-model="form.region" placeholder="please select your zone">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="Activity time">
<el-col :span="11">
<el-date-picker v-model="form.date1" type="date" placeholder="Pick a date" style="width: 100%" />
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker v-model="form.date2" placeholder="Pick a time" style="width: 100%" />
</el-col>
</el-form-item>
<el-form-item label="Instant delivery">
<el-switch v-model="form.delivery" />
</el-form-item>
<el-form-item label="Activity type">
<el-checkbox-group v-model="form.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="Resources">
<el-radio-group v-model="form.resource">
<el-radio label="Sponsor" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="Activity form">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">Create</el-button>
<el-button>Cancel</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
// do not use same name with ref
const form = reactive({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const onSubmit = () => {
console.log('submit!')
}
</script>
B.vue
<template>
<h1 style="margin: 10px;">我是B組件</h1>
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize"
status-icon>
<el-form-item label="Activity name" prop="name">
<el-input v-model="ruleForm.name" />
</el-form-item>
<el-form-item label="Activity zone" prop="region">
<el-select v-model="ruleForm.region" placeholder="Activity zone">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="Activity count" prop="count">
<el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" />
</el-form-item>
<el-form-item label="Activity time" required>
<el-col :span="11">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" label="Pick a date" placeholder="Pick a date"
style="width: 100%" />
</el-form-item>
</el-col>
<el-col class="text-center" :span="2">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-form-item prop="date2">
<el-time-picker v-model="ruleForm.date2" label="Pick a time" placeholder="Pick a time" style="width: 100%" />
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="Instant delivery" prop="delivery">
<el-switch v-model="ruleForm.delivery" />
</el-form-item>
<el-form-item label="Activity type" prop="type">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="Resources" prop="resource">
<el-radio-group v-model="ruleForm.resource">
<el-radio label="Sponsorship" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="Activity form" prop="desc">
<el-input v-model="ruleForm.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">
Create
</el-button>
<el-button @click="resetForm(ruleFormRef)">Reset</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
interface RuleForm {
name: string
region: string
count: string
date1: string
date2: string
delivery: boolean
type: string[]
resource: string
desc: string
}
const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive<RuleForm>({
name: '',
region: '',
count: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const rules = reactive<FormRules<RuleForm>>({
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
region: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change',
},
],
count: [
{
required: true,
message: 'Please select Activity count',
trigger: 'change',
},
],
date1: [
{
type: 'date',
required: true,
message: 'Please pick a date',
trigger: 'change',
},
],
date2: [
{
type: 'date',
required: true,
message: 'Please pick a time',
trigger: 'change',
},
],
type: [
{
type: 'array',
required: true,
message: 'Please select at least one activity type',
trigger: 'change',
},
],
resource: [
{
required: true,
message: 'Please select activity resource',
trigger: 'change',
},
],
desc: [
{ required: true, message: 'Please input activity form', trigger: 'blur' },
],
})
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
const options = Array.from({ length: 10000 }).map((_, idx) => ({
value: `${idx + 1}`,
label: `${idx + 1}`,
}))
</script>
3. 因注釋導致的意外錯誤
寫入注釋:
報錯:
因此 keep-alive
組件內(nèi)不要使用注釋,會被解析為子節(jié)點
解決方法:
-
keep-alive
內(nèi)部不寫注釋 -
使用
<template>
或其他組件標簽將它們包裹起來- 此時 可以認為 利用了
keep-alive
標簽里面有且只有一個子節(jié)點(或者說只能渲染一個子節(jié)點)
- 此時 可以認為 利用了
<keep-alive :exclude="['A']">
<template v-if="flag">
<!-- [] 里面名稱是原本的組件名 -->
<AVue></AVue>
</template>
<template v-else>
<B></B>
</template>
</keep-alive>
4. keep-alive 生命周期
<keep-alive>
組件提供了以下兩個主要的生命周期鉤子函數(shù)來管理緩存的組件:
-
activated:被緩存的組件激活時調(diào)用。
-
deactivated:被緩存的組件停用時調(diào)用。
App.vue
<template>
<el-button type="primary" @click="flag = !flag"> 切換組件</el-button>
<!--
props介紹:
:exclude="['A']" 不緩存A組件
:include="['A']" 緩存A組件
:max="2" 最多緩存2個,如有多個從后往前算起
-->
<keep-alive :exclude="['B']">
<AVue v-if="flag"></AVue>
<B v-else></B>
</keep-alive>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import AVue from './components/A.vue'
import B from './components/B.vue'
const flag = ref<boolean>(true)
</script>
<style scoped></style>
A.vue
<template>
<h1 style="margin: 10px;">我是A組件</h1>
<el-form :model="form" label-width="120px">
<el-form-item label="Activity name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="Activity zone">
<el-select v-model="form.region" placeholder="please select your zone">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="Activity time">
<el-col :span="11">
<el-date-picker v-model="form.date1" type="date" placeholder="Pick a date" style="width: 100%" />
</el-col>
<el-col :span="2" class="text-center">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-time-picker v-model="form.date2" placeholder="Pick a time" style="width: 100%" />
</el-col>
</el-form-item>
<el-form-item label="Instant delivery">
<el-switch v-model="form.delivery" />
</el-form-item>
<el-form-item label="Activity type">
<el-checkbox-group v-model="form.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="Resources">
<el-radio-group v-model="form.resource">
<el-radio label="Sponsor" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="Activity form">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">Create</el-button>
<el-button>Cancel</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive,onMounted,onUnmounted,onDeactivated,onActivated } from 'vue'
// do not use same name with ref
const form = reactive({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const onSubmit = () => {
console.log('submit!')
}
onMounted(() => {
console.log('初始化')
}),
onActivated(() => {
console.log('keep-alive初始化')
})
onDeactivated(() => {
console.log('keep-alive銷毀')
})
onUnmounted(() => {
console.log('銷毀')
})
</script>
B.vue文章來源:http://www.zghlxwxcb.cn/news/detail-645190.html
<template>
<h1 style="margin: 10px;">我是B組件</h1>
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize"
status-icon>
<el-form-item label="Activity name" prop="name">
<el-input v-model="ruleForm.name" />
</el-form-item>
<el-form-item label="Activity zone" prop="region">
<el-select v-model="ruleForm.region" placeholder="Activity zone">
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
<el-form-item label="Activity count" prop="count">
<el-select-v2 v-model="ruleForm.count" placeholder="Activity count" :options="options" />
</el-form-item>
<el-form-item label="Activity time" required>
<el-col :span="11">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" label="Pick a date" placeholder="Pick a date"
style="width: 100%" />
</el-form-item>
</el-col>
<el-col class="text-center" :span="2">
<span class="text-gray-500">-</span>
</el-col>
<el-col :span="11">
<el-form-item prop="date2">
<el-time-picker v-model="ruleForm.date2" label="Pick a time" placeholder="Pick a time" style="width: 100%" />
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="Instant delivery" prop="delivery">
<el-switch v-model="ruleForm.delivery" />
</el-form-item>
<el-form-item label="Activity type" prop="type">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="Online activities" name="type" />
<el-checkbox label="Promotion activities" name="type" />
<el-checkbox label="Offline activities" name="type" />
<el-checkbox label="Simple brand exposure" name="type" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="Resources" prop="resource">
<el-radio-group v-model="ruleForm.resource">
<el-radio label="Sponsorship" />
<el-radio label="Venue" />
</el-radio-group>
</el-form-item>
<el-form-item label="Activity form" prop="desc">
<el-input v-model="ruleForm.desc" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">
Create
</el-button>
<el-button @click="resetForm(ruleFormRef)">Reset</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
interface RuleForm {
name: string
region: string
count: string
date1: string
date2: string
delivery: boolean
type: string[]
resource: string
desc: string
}
const formSize = ref('default')
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive<RuleForm>({
name: '',
region: '',
count: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const rules = reactive<FormRules<RuleForm>>({
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
region: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change',
},
],
count: [
{
required: true,
message: 'Please select Activity count',
trigger: 'change',
},
],
date1: [
{
type: 'date',
required: true,
message: 'Please pick a date',
trigger: 'change',
},
],
date2: [
{
type: 'date',
required: true,
message: 'Please pick a time',
trigger: 'change',
},
],
type: [
{
type: 'array',
required: true,
message: 'Please select at least one activity type',
trigger: 'change',
},
],
resource: [
{
required: true,
message: 'Please select activity resource',
trigger: 'change',
},
],
desc: [
{ required: true, message: 'Please input activity form', trigger: 'blur' },
],
})
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
const options = Array.from({ length: 10000 }).map((_, idx) => ({
value: `${idx + 1}`,
label: `${idx + 1}`,
}))
</script>
文章來源地址http://www.zghlxwxcb.cn/news/detail-645190.html
到了這里,關(guān)于【Vue3】keep-alive 緩存組件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!