状态管理

Zap Admin Vue3使用Pinia作为状态管理方案,相比Vuex具有更好的TypeScript支持和更简洁的API。

Store的创建

src/stores/ 目录下创建store文件:

// src/stores/user.js
import { defineStore } from 'pinia'
import { login, getUserInfo } from '@/api/user'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: '',
    userInfo: null,
    permissions: []
  }),

  getters: {
    isLoggedIn: (state) => !!state.token,
    username: (state) => state.userInfo?.username,
    avatar: (state) => state.userInfo?.avatar
  },

  actions: {
    async login(credentials) {
      try {
        const { token } = await login(credentials)
        this.token = token
        // 获取用户信息
        await this.fetchUserInfo()
      } catch (error) {
        throw error
      }
    },

    async fetchUserInfo() {
      try {
        const data = await getUserInfo()
        this.userInfo = data
        this.permissions = data.permissions
      } catch (error) {
        throw error
      }
    },

    logout() {
      this.token = ''
      this.userInfo = null
      this.permissions = []
    }
  },

  // 状态持久化
  persist: {
    enabled: true,
    strategies: [
      {
        key: 'user',
        storage: localStorage,
        paths: ['token'] // 只持久化token
      }
    ]
  }
})

Store的使用

在组件中使用store:

// 在组件中使用
import { useUserStore } from '@/stores/user'

const UserProfile = defineComponent({
  setup() {
    const userStore = useUserStore()

    // 使用state
    const username = computed(() => userStore.username)

    // 调用actions
    const handleLogout = async () => {
      await userStore.logout()
      router.push('/login')
    }

    return {
      username,
      handleLogout
    }
  }
})

状态持久化

使用 pinia-plugin-persistedstate 实现状态持久化:

// src/stores/plugins/persist.js
import { createPersistedState } from 'pinia-plugin-persistedstate'

export const persist = createPersistedState({
  key: prefix => `zap-admin-${prefix}`,
  storage: window.localStorage,
  // 序列化函数
  serializer: {
    serialize: JSON.stringify,
    deserialize: JSON.parse
  }
})

Store模块

应用配置Store

// src/stores/app.js
export const useAppStore = defineStore('app', {
  state: () => ({
    sidebar: {
      opened: true,
      withoutAnimation: false
    },
    device: 'desktop',
    size: 'default',
    theme: 'light'
  }),

  actions: {
    toggleSidebar() {
      this.sidebar.opened = !this.sidebar.opened
    },
    closeSidebar() {
      this.sidebar.opened = false
    },
    toggleDevice(device) {
      this.device = device
    },
    setSize(size) {
      this.size = size
    },
    setTheme(theme) {
      this.theme = theme
    }
  },

  persist: {
    enabled: true,
    strategies: [
      {
        key: 'app',
        paths: ['size', 'theme']
      }
    ]
  }
})

权限Store

// src/stores/permission.js
export const usePermissionStore = defineStore('permission', {
  state: () => ({
    routes: [],
    addRoutes: [],
    permissions: []
  }),

  getters: {
    hasPermission: (state) => (permission) => {
      return state.permissions.includes(permission)
    }
  },

  actions: {
    setRoutes(routes) {
      this.addRoutes = routes
      this.routes = constantRoutes.concat(routes)
    },

    setPermissions(permissions) {
      this.permissions = permissions
    }
  }
})

最佳实践

  • 按功能模块拆分store
  • 使用TypeScript获得更好的类型提示
  • 合理使用getters避免重复计算
  • 在actions中处理异步逻辑
  • 谨慎使用状态持久化,只持久化必要的数据

Store组织结构

src/stores/
├── modules/          # 功能模块store
│   ├── user.ts
│   ├── app.ts
│   └── permission.ts
├── plugins/          # store插件
│   └── persist.ts
└── index.ts         # store入口文件