Vue 3 与 Keep-alive
Source: Dev.to
问题
在一个有两个标签页的界面 – 疑问(FAQ) 和 表单 – 用户在切换标签页时会失去在表单中输入的所有内容。表单组件被销毁并重新创建,导致状态丢失。
初始解决方案(繁琐)
在每次对 localStorage 进行更改时保存数据,并在提交表单时清除键。可行,但需要大量手动代码和外部状态管理。
优雅的 Vue 解决方案
Vue 拥有 <keep-alive> 组件(内置且抽象)。它不会生成任何真实的 HTML 元素;只会指示 Vue 缓存 组件,而不是在切换标签页时销毁它。这样,表单及其数据就会以极少的开销保留在内存中。
1️⃣ 接收标签页的页面
import { shallowRef } from "vue";
import AbaFormulario from "../components/AbaFormulario.vue";
import AbaDuvidas from "../components/AbaDuvidas.vue";
const abaAtual = shallowRef(AbaFormulario);<div class="botoes-abas">
<button @click="abaAtual = AbaFormulario" :class="{ ativo: abaAtual === AbaFormulario }">
Preencher Formulário
</button>
<button @click="abaAtual = AbaDuvidas" :class="{ ativo: abaAtual === AbaDuvidas }">
Dúvidas Frequentes
</button>
</div>
<keep-alive>
<component :is="abaAtual" />
</keep-alive>.ativo {
font-weight: bold;
background-color: #e0e0e0;
color: var(--black);
}
.botoes-abas {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
<keep-alive>包裹动态组件。在示例中我们使用标签页,但它可以是任何.vue组件(甚至是页面)。
2️⃣ 组件 AbaFormulario
<script setup>
import { ref, onActivated, onDeactivated } from "vue";
const formData = ref({
nome: "",
email: "",
mensagem: "",
});
onActivated(() => {
console.log("Formulário ATIVADO (Recuperado do cache)");
});
onDeactivated(() => {
console.log("Formulário DESATIVADO (Guardado no cache)");
});
</script>
<template>
<div class="formulario-container">
<h2>填写您的信息</h2>
<p>开始输入,切换标签页后再返回。您的数据将会保留在这里!</p>
<div class="campo">
<label>姓名:</label>
<input v-model="formData.nome" type="text" />
</div>
<div class="campo">
<label>电子邮件:</label>
<input v-model="formData.email" type="email" />
</div>
<div class="campo">
<label>留言:</label>
<textarea v-model="formData.mensagem"></textarea>
</div>
<button>发送</button>
</div>
</template>.formulario-container {
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
}
.campo {
margin-bottom: 15px;
display: flex;
flex-direction: column;
}
input,
textarea {
padding: 8px;
margin-top: 5px;
border: 1px solid #999;
border-radius: 4px;
}
button {
padding: 10px 15px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}使用 <keep-alive> 的生命周期
| 钩子 | 触发时机 |
|---|---|
onActivated | 当组件实例从缓存插入到 DOM 后。 |
onDeactivated | 当组件实例从 DOM 中移除并存入缓存后。 |
<template>
<div class="duvidas-container">
<h2>常见问题 (FAQ)</h2>
<p>这里是对最常见问题的回答。</p>
<div class="faq-item">
<h3>我需要填写表单的所有字段吗?</h3>
<p>是的,所有字段都是必填的,以便我们能够高效地联系您。</p>
</div>
<div class="faq-item">
<h3>响应时间是多久?</h3>
<p>我们的团队通常在最多 24 个工作小时内回复。</p>
</div>
</div>
</template>.duvidas-container {
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
background-color: var(--black);
}
.faq-item {
margin-top: 15px;
padding-bottom: 10px;
border-bottom: 1px dashed #ccc;
}
h3 {
margin-bottom: 5px;
color: var(--white);
font-size: 1.1em;
}结论
使用 <keep-alive> 和 onActivated / onDeactivated 钩子,我们能够 保留表单状态 在切换标签页时,无需 localStorage 或外部状态管理。实现简短、清晰,显著提升用户体验。
退出全屏模式
关于 keep-alive 的注意事项
如果您需要使用 reload 重新加载页面,它将丢失数据,因为这些数据保存在内存中的组件(缓存)里。
我们在客户端使用 keep-alive —— 对 SPA 应用非常有用。
参考
- (未列出任何项目)