刷新页面 → Vuex 数据丢失 → 需要判断“是否刷新” → 如果是,重新请求数据并填充到 Vuex
✅ 最佳解决方案(一步到位)
我们分三步走:
- 监听页面是否刷新
- 如果是刷新,触发重新请求数据的 Action
- 在合适的生命周期(如 App.vue 或 store 初始化)执行
🧩 步骤 1:创建判断页面是否刷新的工具函数
// utils/pageReload.js
export function isPageReloaded() {
// ✅ 优先使用标准 Performance API(现代浏览器)
if (performance.getEntriesByType) {
const [navEntry] = performance.getEntriesByType('navigation')
if (navEntry) {
return navEntry.type === 'reload'
}
}
// 降级使用旧 API
if (performance.navigation) {
return performance.navigation.type === 1
}
// ⚠️ 降级方案:sessionStorage 标记法(100% 兼容)
const reloaded = sessionStorage.getItem('__PAGE_RELOADED__') === 'true'
if (!reloaded) {
sessionStorage.setItem('__PAGE_RELOADED__', 'true')
}
return reloaded
}
✅ 这个函数能准确判断“页面是否被刷新”,兼容所有浏览器。
🧩 步骤 2:在 Vuex Store 中定义“恢复数据”的 Action
// store/modules/user.js (示例模块)
import api from '@/api'
export default {
namespaced: true,
state: {
profile: null,
token: '',
permissions: [],
},
mutations: {
SET_PROFILE(state, profile) {
state.profile = profile
},
SET_TOKEN(state, token) {
state.token = token
},
SET_PERMISSIONS(state, permissions) {
state.permissions = permissions
},
},
actions: {
// ✅ 关键:重新拉取用户数据并填充 Vuex
async restoreUserData({ commit, state }) {
try {
// 如果已有 token(比如存在 localStorage),才请求
const token = localStorage.getItem('token')
if (!token) return
// 1. 设置 token
commit('SET_TOKEN', token)
// 2. 请求用户信息
const profile = await api.getUserProfile()
commit('SET_PROFILE', profile)
// 3. 请求权限
const permissions = await api.getUserPermissions()
commit('SET_PERMISSIONS', permissions)
console.log('✅ 刷新页面后,已重新加载用户数据到 Vuex')
} catch (error) {
console.error('❌ 恢复用户数据失败', error)
// 可选:跳转到登录页
// router.push('/login')
}
}
}
}
💡 你也可以在根 store 或其他模块中定义类似
restoreAppData
的 Action。
🧩 步骤 3:在 App.vue 或 store 初始化时触发恢复
✅ 推荐方式:在 App.vue
的 mounted
中判断并恢复
<!-- App.vue -->
<script>
import { mapActions } from 'vuex'
import { isPageReloaded } from '@/utils/pageReload'
export default {
async mounted() {
// 👇 判断是否是刷新页面
if (isPageReloaded()) {
console.log('监听页面刷新,正在恢复 Vuex 数据...')
// 👇 调用 Vuex Action 重新请求数据
await this.restoreUserData()
// 如果有其他模块数据,也可以在这里恢复
// await this.restoreCartData()
// await this.restoreSettings()
}
},
methods: {
...mapActions('user', ['restoreUserData']),
// ...mapActions('cart', ['restoreCartData']),
}
}
</script>
✅ 为什么在
App.vue
?因为它是应用根组件,确保在任何页面渲染前执行。
🧩 步骤 4(可选):在路由守卫中恢复(适合权限控制场景)
如果你用 Vue Router,也可以在全局前置守卫中恢复:
// router/index.js
import { isPageReloaded } from '@/utils/pageReload'
import store from '@/store'
router.beforeEach(async (to, from, next) => {
if (isPageReloaded() && !store.state.user.profile) {
await store.dispatch('user/restoreUserData')
}
next()
})
⚠️ 注意避免重复触发:可以加个标记,比如
store.state.app.restored = true
✅ 完整流程总结
步骤 | 做什么 |
---|---|
1 | 用 isPageReloaded() 判断是否刷新 |
2 | 在 App.vue 的 mounted 中调用 |
3 | 触发 Vuex Action:restoreUserData()
|
4 | Action 内部从 API 重新请求数据并 commit 到 state |
5 | 页面组件从 Vuex 读取数据 → 数据已恢复 ✅ |
✅ 优化建议
1. 避免重复恢复
// store/modules/app.js
state: {
restoredAfterReload: false
},
mutations: {
SET_RESTORED(state) {
state.restoredAfterReload = true
}
},
actions: {
async restoreAfterReload({ state, commit, dispatch }) {
if (state.restoredAfterReload) return // 👈 避免重复执行
await dispatch('user/restoreUserData')
commit('SET_RESTORED')
}
}
2. 显示加载状态(用户体验)
<!-- App.vue -->
<template>
<div id="app">
<div v-if="isLoading" class="loading">正在恢复数据...</div>
<router-view v-else />
</div>
</template>
<script>
export default {
data() {
return {
isLoading: false
}
},
async mounted() {
if (isPageReloaded()) {
this.isLoading = true
await this.restoreAfterReload()
this.isLoading = false
}
},
methods: {
...mapActions('app', ['restoreAfterReload'])
}
}
</script>
3. 结合 localStorage 缓存 token / 用户ID,避免无意义请求
// 在 restoreUserData 中:
const token = localStorage.getItem('token')
if (!token) {
// 没有 token,跳转登录
this.$router.push('/login')
return
}
✅ 最终效果
- 用户刷新页面 → Vuex 数据丢失 ❌
- 系统自动检测到“刷新” → 自动调用
restoreUserData()
✅ - 重新请求 API → 填充 Vuex → 页面组件正常渲染 ✅
- 用户无感知,体验无缝!
🚀 Bonus:如果你用 Pinia(Vue 3 新推荐状态管理)
逻辑完全一样:
// stores/user.ts
import { ref } from 'pinia'
import { defineStore } from 'pinia'
import { isPageReloaded } from '@/utils/pageReload'
export const useUserStore = defineStore('user', () => {
const profile = ref(null)
const token = ref('')
async function restoreUserData() {
const t = localStorage.getItem('token')
if (!t) return
token.value = t
profile.value = await api.getUserProfile()
}
// 自动恢复
if (isPageReloaded()) {
restoreUserData()
}
return { profile, token, restoreUserData }
})
✅ 你现在就可以:
- 创建
utils/pageReload.js
- 在 Vuex 模块中添加
restoreUserData
Action - 在
App.vue
的mounted
中调用 - 刷新页面 → 数据自动恢复!
需要我帮你根据你的具体 Vuex 模块结构定制代码吗?贴出来,我来帮你写 👍