欢迎光临焦作中国转运服务网
详情描述

1. keep-alive 组件缓存

基本用法

<!-- App.vue -->
<template>
  <div id="app">
    <keep-alive :include="cachedComponents">
      <router-view />
    </keep-alive>
  </div>
</template>

<script>
export default {
  data() {
    return {
      cachedComponents: ['Home', 'UserList'] // 要缓存的组件名
    }
  }
}
</script>

结合路由的缓存策略

// router/index.js
const routes = [
  {
    path: '/home',
    name: 'Home',
    component: () => import('./views/Home.vue'),
    meta: {
      keepAlive: true  // 需要缓存
    }
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('./views/Login.vue'),
    meta: {
      keepAlive: false // 不需要缓存
    }
  }
]
<!-- App.vue -->
<template>
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive" />
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive" />
</template>

keep-alive 生命周期钩子

<script>
export default {
  name: 'MyComponent',
  activated() {
    // 组件被激活时调用
    console.log('组件被激活,恢复状态')
  },
  deactivated() {
    // 组件被停用时调用
    console.log('组件被停用,保存状态')
  }
}
</script>

2. 状态管理 (Vuex/Pinia)

Vuex 持久化

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  user: null,
  settings: {}
}

const mutations = {
  SET_USER(state, user) {
    state.user = user
    // 保存到 localStorage
    if (user) {
      localStorage.setItem('user', JSON.stringify(user))
    } else {
      localStorage.removeItem('user')
    }
  },
  LOAD_PERSISTED_STATE(state) {
    // 加载持久化状态
    const user = localStorage.getItem('user')
    if (user) {
      state.user = JSON.parse(user)
    }
  }
}

export default new Vuex.Store({
  state,
  mutations,
  // 可选:使用插件自动持久化
  plugins: [
    store => {
      // 初始化时加载
      store.commit('LOAD_PERSISTED_STATE')

      // 监听变化并保存
      store.subscribe((mutation, state) => {
        if (mutation.type === 'SET_USER') {
          localStorage.setItem('user', JSON.stringify(state.user))
        }
      })
    }
  ]
})

Pinia 持久化

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    lastVisited: null
  }),
  actions: {
    increment() {
      this.count++
      this.saveToStorage()
    },
    saveToStorage() {
      localStorage.setItem('counterStore', JSON.stringify(this.$state))
    },
    loadFromStorage() {
      const saved = localStorage.getItem('counterStore')
      if (saved) {
        this.$state = JSON.parse(saved)
      }
    }
  }
})

3. 浏览器存储 API

封装存储工具类

// utils/storage.js
class StorageHelper {
  constructor(namespace = 'app') {
    this.namespace = namespace
  }

  set(key, value) {
    const data = this.getAll()
    data[key] = value
    localStorage.setItem(this.namespace, JSON.stringify(data))
  }

  get(key, defaultValue = null) {
    const data = this.getAll()
    return data[key] || defaultValue
  }

  getAll() {
    const data = localStorage.getItem(this.namespace)
    return data ? JSON.parse(data) : {}
  }

  remove(key) {
    const data = this.getAll()
    delete data[key]
    localStorage.setItem(this.namespace, JSON.stringify(data))
  }

  clear() {
    localStorage.removeItem(this.namespace)
  }
}

// 使用示例
const pageStorage = new StorageHelper('pageState')

// 在组件中使用
export default {
  data() {
    return {
      formData: {}
    }
  },
  created() {
    // 加载保存的状态
    const saved = pageStorage.get(this.$route.path)
    if (saved) {
      this.formData = saved
    }
  },
  methods: {
    saveForm() {
      // 保存状态
      pageStorage.set(this.$route.path, this.formData)
    }
  },
  beforeRouteLeave(to, from, next) {
    // 离开页面时保存状态
    pageStorage.set(from.path, this.formData)
    next()
  }
}

4. 路由守卫 + 本地存储

// router/index.js
const router = new VueRouter({ ... })

// 页面状态管理器
const pageStateManager = {
  saveState(route, state) {
    const key = `page_state_${route.path}`
    localStorage.setItem(key, JSON.stringify(state))
  },

  loadState(route) {
    const key = `page_state_${route.path}`
    const saved = localStorage.getItem(key)
    return saved ? JSON.parse(saved) : null
  },

  clearState(route) {
    const key = `page_state_${route.path}`
    localStorage.removeItem(key)
  }
}

// 全局路由守卫
router.beforeEach((to, from, next) => {
  // 如果需要保存离开页面的状态
  if (from.matched.some(record => record.meta.saveState)) {
    const component = router.app.$children.find(
      child => child.$vnode && child.$vnode.tag.includes(from.name)
    )
    if (component && component.getPageState) {
      const state = component.getPageState()
      pageStateManager.saveState(from, state)
    }
  }

  // 如果需要恢复目标页面的状态
  if (to.matched.some(record => record.meta.restoreState)) {
    const savedState = pageStateManager.loadState(to)
    to.meta.savedState = savedState
  }

  next()
})

5. 组件状态保存的最佳实践

混合方案示例

<template>
  <div>
    <!-- 表单组件 -->
    <input v-model="formData.name" />
    <input v-model="formData.email" />
    <button @click="saveForm">保存</button>
  </div>
</template>

<script>
import { debounce } from 'lodash'

export default {
  name: 'MyFormPage',
  data() {
    return {
      formData: {
        name: '',
        email: ''
      },
      isDataLoaded: false
    }
  },

  created() {
    this.loadSavedData()
    // 防抖保存
    this.debouncedSave = debounce(this.autoSave, 1000)
  },

  activated() {
    // keep-alive 激活时调用
    if (!this.isDataLoaded) {
      this.loadSavedData()
    }
  },

  deactivated() {
    // keep-alive 停用时自动保存
    this.autoSave()
  },

  methods: {
    loadSavedData() {
      // 从多个源加载数据
      const savedData = 
        localStorage.getItem(`form_${this.$route.path}`) ||
        this.$store.getters.getPageState(this.$route.path)

      if (savedData) {
        this.formData = JSON.parse(savedData)
        this.isDataLoaded = true
      }
    },

    saveForm() {
      // 保存到本地存储
      localStorage.setItem(
        `form_${this.$route.path}`,
        JSON.stringify(this.formData)
      )
      // 保存到 Vuex
      this.$store.commit('SAVE_PAGE_STATE', {
        path: this.$route.path,
        data: this.formData
      })
    },

    autoSave() {
      if (this.formData.name || this.formData.email) {
        localStorage.setItem(
          `form_${this.$route.path}_autosave`,
          JSON.stringify(this.formData)
        )
      }
    }
  },

  watch: {
    formData: {
      deep: true,
      handler() {
        this.debouncedSave()
      }
    }
  }
}
</script>

6. 第三方库推荐

vuex-persistedstate

npm install vuex-persistedstate
import createPersistedState from 'vuex-persistedstate'

export default new Vuex.Store({
  // ...
  plugins: [
    createPersistedState({
      key: 'vuex',
      storage: window.localStorage,
      reducer: (state) => ({
        user: state.user,
        settings: state.settings
      })
    })
  ]
})

pinia-plugin-persistedstate

npm install pinia-plugin-persistedstate
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

// 在 store 中使用
export const useUserStore = defineStore('user', {
  state: () => ({
    user: null
  }),
  persist: {
    enabled: true,
    strategies: [
      {
        key: 'user',
        storage: localStorage
      }
    ]
  }
})

选择建议

页面级缓存:使用 keep-alive 用户数据持久化:使用 Vuex/Pinia + 本地存储 表单状态临时保存:使用路由守卫 + sessionStorage 复杂应用:混合使用多种方案 SEO敏感页面:避免使用 keep-alive,改用服务端存储

根据具体需求选择合适的方案或组合使用多种方案,可以实现更灵活的状态管理。

相关帖子