前言
我们在做工具类网站(比如 JSON 格式化、Base64 转换)时,经常遇到一个痛点:用户如果不小心刷新了页面,刚刚输入的一大段内容或者辛苦调整的配置项(比如“缩进2空格”、“深色模式”)就全丢了。
在开发我的个人项目 SonicToolLab 时,为了提升这种“无感”的用户体验,我使用了 Pinia 配合 持久化插件。
今天分享在 Nuxt 4 中如何极其优雅地实现这一功能。
📦 1. 为什么是 Pinia?
在 Vue 3 和 Nuxt 4 时代,Vuex 已经成为历史。Pinia 不仅体积更小,而且对 TypeScript 的支持是原生的,写起来非常有安全感。
在 Nuxt 4 中使用 Pinia 甚至不需要手动 import,官方模块已经帮我们要好了所有配置。
安装
pnpm add @pinia/nuxt pinia
配置 nuxt.config.ts
TypeScript
export default defineNuxtConfig({
modules: [
'@pinia/nuxt'
],
})
💾 2. 核心魔法:数据持久化 (Persistedstate)
光有 Pinia 只是存在内存里,刷新就没了。我们需要把 State 自动同步到 localStorage 中。这里推荐 pinia-plugin-persistedstate。
安装插件
pnpm add @pinia-plugin-persistedstate/nuxt
启用配置
TypeScript
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@pinia/nuxt',
'@pinia-plugin-persistedstate/nuxt' // 引入持久化模块
],
})
🛠️ 3. 实战代码:记录用户的“操作历史”
在 SonicToolLab 中,我希望记录用户最近使用的 5 个工具,方便他们下次直接点击。
看看代码有多简洁:
TypeScript
// stores/history.ts
export const useHistoryStore = defineStore('history', {
state: () => ({
recentTools: [] as string[]
}),
actions: {
addRecord(toolName: string) {
// 简单的去重逻辑,保持最近5个
this.recentTools = this.recentTools.filter(t => t !== toolName)
this.recentTools.unshift(toolName)
if (this.recentTools.length > 5) this.recentTools.pop()
}
},
// 🔥 关键一行:开启持久化
persist: true
})
在页面中使用
Code snippet
<script setup>
const historyStore = useHistoryStore()
// 当用户进入某个工具页时
onMounted(() => {
historyStore.addRecord('JSON 格式化')
})
</script>
<template>
<div v-if="historyStore.recentTools.length">
最近使用:
<UBadge v-for="tool in historyStore.recentTools" :key="tool">
{{ tool }}
</UBadge>
</div>
</template>
就这么简单!现在,无论用户怎么刷新页面,甚至关闭浏览器再打开,recentTools 里的数据依然存在。
⚠️ 4. 避坑指南:Hydration Mismatch
在 Nuxt (SSR) 中使用 localStorage 持久化,最容易遇到的问题是:服务端渲染时没有 localStorage,而客户端有,导致 HTML 不匹配。
@pinia-plugin-persistedstate/nuxt 默认处理得很好,但如果你发现控制台报 Hydration 错误,可以在组件外层包裹一个 <ClientOnly>,或者确保只在 onMounted 之后再渲染依赖 Store 的 UI。
总结
对于独立开发者来说,Pinia + 持久化插件 是提升工具站 UX(用户体验)性价比最高的组合。它不需要数据库,不需要后端接口,纯前端就能让你的网站显得“很智能”。
这一套逻辑目前稳定运行在我的 SonicToolLab 上,欢迎大家去体验一下“刷新页面数据不丢失”的效果。
下一篇,我们要聊聊工具站中 “如何优雅地处理文件上传与解析(纯前端 vs 服务端中转)” ,敬请期待!