第75天:Element Plus 与 Pinia 状态管理
学习目标
- 掌握 Pinia 在 Element Plus 应用中的最佳实践
- 学习组件状态与全局状态的协调管理
- 了解状态持久化和数据同步策略
- 实现复杂业务场景下的状态管理方案
知识点概览
1. Pinia 与 Element Plus 集成基础
1.1 Pinia 配置与初始化
typescript
// stores/index.ts
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate'
import type { App } from 'vue'
// 创建 Pinia 实例
const pinia = createPinia()
// 配置持久化插件
pinia.use(
createPersistedState({
storage: localStorage,
serializer: {
serialize: JSON.stringify,
deserialize: JSON.parse
},
key: id => `pinia-${id}`,
auto: true
})
)
// 安装 Pinia
export function setupStore(app: App) {
app.use(pinia)
}
export { pinia }
export default pinia
1.2 状态管理架构设计
typescript
// types/store.ts
// 基础状态接口
export interface BaseState {
loading: boolean
error: string | null
lastUpdated: number
}
// 分页状态接口
export interface PaginationState {
current: number
pageSize: number
total: number
showSizeChanger: boolean
showQuickJumper: boolean
pageSizes: number[]
}
// 表格状态接口
export interface TableState extends BaseState {
data: any[]
selectedRows: any[]
pagination: PaginationState
filters: Record<string, any>
sorter: {
field?: string
order?: 'ascend' | 'descend'
}
columns: any[]
}
// 表单状态接口
export interface FormState extends BaseState {
data: Record<string, any>
rules: Record<string, any>
disabled: boolean
readonly: boolean
mode: 'create' | 'edit' | 'view'
}
// 用户状态接口
export interface UserState extends BaseState {
userInfo: {
id: string
username: string
nickname: string
avatar: string
email: string
phone: string
roles: string[]
permissions: string[]
}
token: string
refreshToken: string
loginTime: number
lastActiveTime: number
}
// 应用状态接口
export interface AppState {
theme: 'light' | 'dark'
locale: string
sidebar: {
collapsed: boolean
width: number
}
device: 'desktop' | 'tablet' | 'mobile'
size: 'large' | 'default' | 'small'
}
2. 核心状态管理模块
2.1 用户状态管理
typescript
// stores/user.ts
import { defineStore } from 'pinia'
import { ElMessage, ElMessageBox } from 'element-plus'
import { login, logout, getUserInfo, refreshToken } from '@/api/auth'
import { removeToken, setToken, getToken } from '@/utils/auth'
import type { UserState } from '@/types/store'
export const useUserStore = defineStore('user', {
state: (): UserState => ({
userInfo: {
id: '',
username: '',
nickname: '',
avatar: '',
email: '',
phone: '',
roles: [],
permissions: []
},
token: getToken() || '',
refreshToken: '',
loginTime: 0,
lastActiveTime: Date.now(),
loading: false,
error: null,
lastUpdated: 0
}),
getters: {
// 是否已登录
isLoggedIn: (state) => !!state.token,
// 是否为管理员
isAdmin: (state) => state.userInfo.roles.includes('admin'),
// 获取用户显示名称
displayName: (state) => {
return state.userInfo.nickname || state.userInfo.username || '未知用户'
},
// 检查是否有指定权限
hasPermission: (state) => (permission: string) => {
return state.userInfo.permissions.includes(permission)
},
// 检查是否有指定角色
hasRole: (state) => (role: string) => {
return state.userInfo.roles.includes(role)
},
// 检查是否有任一权限
hasAnyPermission: (state) => (permissions: string[]) => {
return permissions.some(permission =>
state.userInfo.permissions.includes(permission)
)
},
// 检查是否有所有权限
hasAllPermissions: (state) => (permissions: string[]) => {
return permissions.every(permission =>
state.userInfo.permissions.includes(permission)
)
},
// 是否需要刷新token
needRefreshToken: (state) => {
const now = Date.now()
const tokenAge = now - state.loginTime
const maxAge = 7 * 24 * 60 * 60 * 1000 // 7天
return tokenAge > maxAge * 0.8 // 超过80%时间时刷新
}
},
actions: {
// 设置用户信息
setUserInfo(userInfo: Partial<UserState['userInfo']>) {
this.userInfo = { ...this.userInfo, ...userInfo }
this.lastUpdated = Date.now()
},
// 设置token
setToken(token: string) {
this.token = token
setToken(token)
this.loginTime = Date.now()
},
// 设置刷新token
setRefreshToken(refreshToken: string) {
this.refreshToken = refreshToken
},
// 更新最后活跃时间
updateLastActiveTime() {
this.lastActiveTime = Date.now()
},
// 登录
async login(loginForm: { username: string; password: string; captcha?: string }) {
this.loading = true
this.error = null
try {
const response = await login(loginForm)
const { token, refreshToken, userInfo } = response.data
this.setToken(token)
this.setRefreshToken(refreshToken)
this.setUserInfo(userInfo)
ElMessage.success('登录成功')
return response
} catch (error: any) {
this.error = error.message || '登录失败'
ElMessage.error(this.error)
throw error
} finally {
this.loading = false
}
},
// 获取用户信息
async getUserInfo() {
if (!this.token) {
throw new Error('未登录')
}
this.loading = true
this.error = null
try {
const response = await getUserInfo()
this.setUserInfo(response.data)
return response.data
} catch (error: any) {
this.error = error.message || '获取用户信息失败'
throw error
} finally {
this.loading = false
}
},
// 刷新token
async refreshUserToken() {
if (!this.refreshToken) {
throw new Error('无刷新token')
}
try {
const response = await refreshToken(this.refreshToken)
const { token, refreshToken: newRefreshToken } = response.data
this.setToken(token)
this.setRefreshToken(newRefreshToken)
return response
} catch (error) {
// 刷新失败,清除所有信息
await this.logout()
throw error
}
},
// 登出
async logout(showConfirm = false) {
if (showConfirm) {
try {
await ElMessageBox.confirm(
'确定要退出登录吗?',
'提示',
{
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消'
}
)
} catch {
return
}
}
try {
if (this.token) {
await logout()
}
} catch (error) {
console.error('登出请求失败:', error)
} finally {
// 清除本地状态
this.token = ''
this.refreshToken = ''
this.userInfo = {
id: '',
username: '',
nickname: '',
avatar: '',
email: '',
phone: '',
roles: [],
permissions: []
}
this.loginTime = 0
this.lastActiveTime = 0
removeToken()
ElMessage.success('已退出登录')
// 跳转到登录页
window.location.href = '/login'
}
},
// 重置状态
resetState() {
this.$reset()
removeToken()
}
},
persist: {
key: 'user-store',
storage: localStorage,
paths: ['userInfo', 'token', 'refreshToken', 'loginTime']
}
})
2.2 应用状态管理
typescript
// stores/app.ts
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import type { AppState } from '@/types/store'
export const useAppStore = defineStore('app', {
state: (): AppState => ({
theme: 'light',
locale: 'zh-CN',
sidebar: {
collapsed: false,
width: 240
},
device: 'desktop',
size: 'default'
}),
getters: {
// 是否为暗黑主题
isDark: (state) => state.theme === 'dark',
// 是否为移动设备
isMobile: (state) => state.device === 'mobile',
// 侧边栏实际宽度
sidebarWidth: (state) => {
return state.sidebar.collapsed ? 64 : state.sidebar.width
},
// 主内容区域样式
mainContentStyle: (state) => {
const marginLeft = state.sidebar.collapsed ? 64 : state.sidebar.width
return {
marginLeft: `${marginLeft}px`,
transition: 'margin-left 0.3s'
}
}
},
actions: {
// 切换主题
toggleTheme() {
this.theme = this.theme === 'light' ? 'dark' : 'light'
this.applyTheme()
ElMessage.success(`已切换到${this.theme === 'light' ? '浅色' : '深色'}主题`)
},
// 设置主题
setTheme(theme: 'light' | 'dark') {
this.theme = theme
this.applyTheme()
},
// 应用主题
applyTheme() {
const html = document.documentElement
if (this.theme === 'dark') {
html.classList.add('dark')
} else {
html.classList.remove('dark')
}
},
// 设置语言
setLocale(locale: string) {
this.locale = locale
// 这里可以触发国际化更新
ElMessage.success('语言设置已更新')
},
// 切换侧边栏
toggleSidebar() {
this.sidebar.collapsed = !this.sidebar.collapsed
},
// 设置侧边栏状态
setSidebarCollapsed(collapsed: boolean) {
this.sidebar.collapsed = collapsed
},
// 设置侧边栏宽度
setSidebarWidth(width: number) {
this.sidebar.width = Math.max(200, Math.min(400, width))
},
// 设置设备类型
setDevice(device: 'desktop' | 'tablet' | 'mobile') {
this.device = device
// 移动设备自动收起侧边栏
if (device === 'mobile') {
this.sidebar.collapsed = true
}
},
// 设置组件尺寸
setSize(size: 'large' | 'default' | 'small') {
this.size = size
},
// 初始化应用设置
initializeApp() {
this.applyTheme()
this.detectDevice()
},
// 检测设备类型
detectDevice() {
const width = window.innerWidth
if (width < 768) {
this.setDevice('mobile')
} else if (width < 1024) {
this.setDevice('tablet')
} else {
this.setDevice('desktop')
}
}
},
persist: {
key: 'app-store',
storage: localStorage
}
})
3. 业务状态管理模块
3.1 表格状态管理
typescript
// stores/table.ts
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import type { TableState } from '@/types/store'
// 创建表格状态管理工厂
export function createTableStore(name: string, api: any) {
return defineStore(`table-${name}`, {
state: (): TableState => ({
data: [],
selectedRows: [],
pagination: {
current: 1,
pageSize: 20,
total: 0,
showSizeChanger: true,
showQuickJumper: true,
pageSizes: [10, 20, 50, 100]
},
filters: {},
sorter: {},
columns: [],
loading: false,
error: null,
lastUpdated: 0
}),
getters: {
// 是否有选中行
hasSelectedRows: (state) => state.selectedRows.length > 0,
// 选中行数量
selectedCount: (state) => state.selectedRows.length,
// 是否全选
isAllSelected: (state) => {
return state.data.length > 0 &&
state.selectedRows.length === state.data.length
},
// 是否部分选中
isIndeterminate: (state) => {
return state.selectedRows.length > 0 &&
state.selectedRows.length < state.data.length
},
// 分页信息
paginationInfo: (state) => {
const { current, pageSize, total } = state.pagination
const start = (current - 1) * pageSize + 1
const end = Math.min(current * pageSize, total)
return { start, end, total }
}
},
actions: {
// 加载数据
async loadData(params: any = {}) {
this.loading = true
this.error = null
try {
const requestParams = {
page: this.pagination.current,
pageSize: this.pagination.pageSize,
...this.filters,
...this.sorter,
...params
}
const response = await api.getList(requestParams)
const { data, total } = response.data
this.data = data
this.pagination.total = total
this.lastUpdated = Date.now()
return response
} catch (error: any) {
this.error = error.message || '加载数据失败'
ElMessage.error(this.error)
throw error
} finally {
this.loading = false
}
},
// 刷新数据
async refresh() {
await this.loadData()
},
// 重置并加载
async reset() {
this.pagination.current = 1
this.filters = {}
this.sorter = {}
this.selectedRows = []
await this.loadData()
},
// 设置分页
setPagination(pagination: Partial<TableState['pagination']>) {
this.pagination = { ...this.pagination, ...pagination }
},
// 页码变化
async handlePageChange(page: number) {
this.pagination.current = page
await this.loadData()
},
// 页大小变化
async handlePageSizeChange(pageSize: number) {
this.pagination.pageSize = pageSize
this.pagination.current = 1
await this.loadData()
},
// 设置过滤器
async setFilters(filters: Record<string, any>) {
this.filters = { ...filters }
this.pagination.current = 1
await this.loadData()
},
// 设置排序
async setSorter(sorter: { field?: string; order?: 'ascend' | 'descend' }) {
this.sorter = { ...sorter }
await this.loadData()
},
// 选择行
setSelectedRows(rows: any[]) {
this.selectedRows = [...rows]
},
// 选择单行
toggleRowSelection(row: any, selected?: boolean) {
const index = this.selectedRows.findIndex(item => item.id === row.id)
if (selected === undefined) {
selected = index === -1
}
if (selected && index === -1) {
this.selectedRows.push(row)
} else if (!selected && index !== -1) {
this.selectedRows.splice(index, 1)
}
},
// 全选/取消全选
toggleAllSelection(selected?: boolean) {
if (selected === undefined) {
selected = !this.isAllSelected
}
this.selectedRows = selected ? [...this.data] : []
},
// 清除选择
clearSelection() {
this.selectedRows = []
},
// 删除选中行
async deleteSelected() {
if (this.selectedRows.length === 0) {
ElMessage.warning('请选择要删除的数据')
return
}
try {
const ids = this.selectedRows.map(row => row.id)
await api.batchDelete(ids)
ElMessage.success('删除成功')
this.clearSelection()
await this.refresh()
} catch (error: any) {
ElMessage.error(error.message || '删除失败')
throw error
}
},
// 添加数据
async addItem(item: any) {
try {
const response = await api.create(item)
ElMessage.success('添加成功')
await this.refresh()
return response
} catch (error: any) {
ElMessage.error(error.message || '添加失败')
throw error
}
},
// 更新数据
async updateItem(id: string, item: any) {
try {
const response = await api.update(id, item)
ElMessage.success('更新成功')
await this.refresh()
return response
} catch (error: any) {
ElMessage.error(error.message || '更新失败')
throw error
}
},
// 删除数据
async deleteItem(id: string) {
try {
await api.delete(id)
ElMessage.success('删除成功')
await this.refresh()
} catch (error: any) {
ElMessage.error(error.message || '删除失败')
throw error
}
}
}
})
}
// 用户表格状态
export const useUserTableStore = createTableStore('user', {
getList: (params: any) => import('@/api/user').then(m => m.getUserList(params)),
create: (data: any) => import('@/api/user').then(m => m.createUser(data)),
update: (id: string, data: any) => import('@/api/user').then(m => m.updateUser(id, data)),
delete: (id: string) => import('@/api/user').then(m => m.deleteUser(id)),
batchDelete: (ids: string[]) => import('@/api/user').then(m => m.batchDeleteUsers(ids))
})
3.2 表单状态管理
typescript
// stores/form.ts
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import type { FormState } from '@/types/store'
// 创建表单状态管理工厂
export function createFormStore(name: string, api: any, initialData: any = {}) {
return defineStore(`form-${name}`, {
state: (): FormState => ({
data: { ...initialData },
rules: {},
disabled: false,
readonly: false,
mode: 'create',
loading: false,
error: null,
lastUpdated: 0
}),
getters: {
// 是否为创建模式
isCreateMode: (state) => state.mode === 'create',
// 是否为编辑模式
isEditMode: (state) => state.mode === 'edit',
// 是否为查看模式
isViewMode: (state) => state.mode === 'view',
// 表单是否可编辑
isEditable: (state) => {
return !state.readonly && !state.disabled && state.mode !== 'view'
},
// 获取表单标题
formTitle: (state) => {
const titles = {
create: '新增',
edit: '编辑',
view: '查看'
}
return titles[state.mode]
}
},
actions: {
// 设置表单数据
setData(data: Record<string, any>) {
this.data = { ...this.data, ...data }
this.lastUpdated = Date.now()
},
// 设置字段值
setFieldValue(field: string, value: any) {
this.data[field] = value
this.lastUpdated = Date.now()
},
// 设置表单规则
setRules(rules: Record<string, any>) {
this.rules = { ...rules }
},
// 设置表单模式
setMode(mode: 'create' | 'edit' | 'view') {
this.mode = mode
this.readonly = mode === 'view'
},
// 设置禁用状态
setDisabled(disabled: boolean) {
this.disabled = disabled
},
// 设置只读状态
setReadonly(readonly: boolean) {
this.readonly = readonly
},
// 重置表单
reset() {
this.data = { ...initialData }
this.error = null
this.lastUpdated = Date.now()
},
// 加载数据(编辑/查看模式)
async loadData(id: string) {
if (!id) return
this.loading = true
this.error = null
try {
const response = await api.getById(id)
this.setData(response.data)
return response.data
} catch (error: any) {
this.error = error.message || '加载数据失败'
ElMessage.error(this.error)
throw error
} finally {
this.loading = false
}
},
// 提交表单
async submit() {
this.loading = true
this.error = null
try {
let response
if (this.mode === 'create') {
response = await api.create(this.data)
ElMessage.success('创建成功')
} else if (this.mode === 'edit') {
response = await api.update(this.data.id, this.data)
ElMessage.success('更新成功')
}
return response
} catch (error: any) {
this.error = error.message || '提交失败'
ElMessage.error(this.error)
throw error
} finally {
this.loading = false
}
},
// 验证表单
async validate(formRef: any) {
if (!formRef) {
throw new Error('表单引用不存在')
}
try {
await formRef.validate()
return true
} catch (error) {
ElMessage.error('表单验证失败,请检查输入')
return false
}
},
// 清除验证
clearValidate(formRef: any, fields?: string[]) {
if (formRef) {
formRef.clearValidate(fields)
}
}
}
})
}
// 用户表单状态
export const useUserFormStore = createFormStore('user', {
getById: (id: string) => import('@/api/user').then(m => m.getUserById(id)),
create: (data: any) => import('@/api/user').then(m => m.createUser(data)),
update: (id: string, data: any) => import('@/api/user').then(m => m.updateUser(id, data))
}, {
username: '',
nickname: '',
email: '',
phone: '',
status: 1,
roles: []
})
4. 状态持久化与同步
4.1 高级持久化策略
typescript
// utils/persistence.ts
import { PiniaPluginContext } from 'pinia'
import { watch } from 'vue'
// 持久化配置接口
interface PersistenceConfig {
key?: string
storage?: Storage
paths?: string[]
serializer?: {
serialize: (value: any) => string
deserialize: (value: string) => any
}
beforeRestore?: (context: PiniaPluginContext) => void
afterRestore?: (context: PiniaPluginContext) => void
filter?: (mutation: any) => boolean
}
// 创建持久化插件
export function createPersistencePlugin(defaultConfig: PersistenceConfig = {}) {
return (context: PiniaPluginContext) => {
const { store, options } = context
const config = { ...defaultConfig, ...options.persist }
if (!config || config === false) return
const {
key = store.$id,
storage = localStorage,
paths,
serializer = {
serialize: JSON.stringify,
deserialize: JSON.parse
},
beforeRestore,
afterRestore,
filter
} = config
// 恢复状态
const restore = () => {
try {
beforeRestore?.(context)
const stored = storage.getItem(key)
if (stored) {
const data = serializer.deserialize(stored)
if (paths) {
// 只恢复指定路径的数据
paths.forEach(path => {
if (data[path] !== undefined) {
store.$patch({ [path]: data[path] })
}
})
} else {
// 恢复所有数据
store.$patch(data)
}
}
afterRestore?.(context)
} catch (error) {
console.error('恢复状态失败:', error)
}
}
// 保存状态
const persist = () => {
try {
let data = store.$state
if (paths) {
// 只保存指定路径的数据
data = paths.reduce((acc, path) => {
acc[path] = store.$state[path]
return acc
}, {} as any)
}
storage.setItem(key, serializer.serialize(data))
} catch (error) {
console.error('保存状态失败:', error)
}
}
// 监听状态变化
store.$subscribe((mutation, state) => {
if (!filter || filter(mutation)) {
persist()
}
})
// 初始恢复
restore()
}
}
// 状态同步管理器
class StateSyncManager {
private syncChannels: Map<string, BroadcastChannel> = new Map()
private stores: Map<string, any> = new Map()
// 注册状态同步
registerSync(storeId: string, store: any, options: {
channel?: string
paths?: string[]
debounce?: number
} = {}) {
const {
channel = `sync-${storeId}`,
paths,
debounce = 100
} = options
this.stores.set(storeId, store)
// 创建广播通道
if (!this.syncChannels.has(channel)) {
const bc = new BroadcastChannel(channel)
bc.onmessage = (event) => {
const { type, storeId: sourceStoreId, data } = event.data
if (type === 'state-update' && sourceStoreId !== storeId) {
const targetStore = this.stores.get(storeId)
if (targetStore) {
targetStore.$patch(data)
}
}
}
this.syncChannels.set(channel, bc)
}
const bc = this.syncChannels.get(channel)!
// 防抖发送更新
let timeoutId: number
store.$subscribe((mutation: any, state: any) => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
let data = state
if (paths) {
data = paths.reduce((acc, path) => {
acc[path] = state[path]
return acc
}, {} as any)
}
bc.postMessage({
type: 'state-update',
storeId,
data,
timestamp: Date.now()
})
}, debounce)
})
}
// 取消同步
unregisterSync(storeId: string) {
this.stores.delete(storeId)
}
// 关闭所有通道
closeAllChannels() {
this.syncChannels.forEach(channel => channel.close())
this.syncChannels.clear()
this.stores.clear()
}
}
export const stateSyncManager = new StateSyncManager()
4.2 状态监控与调试
typescript
// utils/storeDevtools.ts
import { PiniaPluginContext } from 'pinia'
// 状态监控插件
export function createDevtoolsPlugin() {
return (context: PiniaPluginContext) => {
const { store } = context
if (process.env.NODE_ENV === 'development') {
// 添加调试方法
store.$debug = {
// 获取状态快照
getSnapshot: () => JSON.parse(JSON.stringify(store.$state)),
// 恢复状态快照
restoreSnapshot: (snapshot: any) => {
store.$patch(snapshot)
},
// 获取状态历史
getHistory: () => store._history || [],
// 清除历史
clearHistory: () => {
if (store._history) {
store._history.length = 0
}
},
// 时间旅行
timeTravel: (index: number) => {
const history = store._history
if (history && history[index]) {
store.$patch(history[index])
}
}
}
// 记录状态历史
if (!store._history) {
store._history = []
}
store.$subscribe((mutation, state) => {
const history = store._history
if (history) {
history.push({
mutation: {
type: mutation.type,
storeId: mutation.storeId,
payload: mutation.payload
},
state: JSON.parse(JSON.stringify(state)),
timestamp: Date.now()
})
// 限制历史记录数量
if (history.length > 50) {
history.shift()
}
}
})
// 性能监控
const originalPatch = store.$patch
store.$patch = function(partialStateOrMutator: any) {
const start = performance.now()
const result = originalPatch.call(this, partialStateOrMutator)
const end = performance.now()
console.log(`[${store.$id}] $patch took ${end - start} milliseconds`)
return result
}
}
}
}
// 状态性能分析器
class StorePerformanceAnalyzer {
private metrics: Map<string, any[]> = new Map()
// 开始监控
startMonitoring(storeId: string, store: any) {
if (!this.metrics.has(storeId)) {
this.metrics.set(storeId, [])
}
const metrics = this.metrics.get(storeId)!
store.$subscribe((mutation: any, state: any) => {
metrics.push({
type: 'mutation',
mutation: mutation.type,
timestamp: Date.now(),
stateSize: JSON.stringify(state).length
})
// 限制指标数量
if (metrics.length > 1000) {
metrics.splice(0, 500)
}
})
}
// 获取性能报告
getPerformanceReport(storeId: string) {
const metrics = this.metrics.get(storeId) || []
if (metrics.length === 0) {
return null
}
const mutationCounts = metrics.reduce((acc, metric) => {
acc[metric.mutation] = (acc[metric.mutation] || 0) + 1
return acc
}, {} as Record<string, number>)
const avgStateSize = metrics.reduce((sum, metric) =>
sum + metric.stateSize, 0
) / metrics.length
const timeRange = {
start: metrics[0]?.timestamp,
end: metrics[metrics.length - 1]?.timestamp
}
return {
storeId,
totalMutations: metrics.length,
mutationCounts,
avgStateSize: Math.round(avgStateSize),
timeRange,
duration: timeRange.end - timeRange.start
}
}
// 清除指标
clearMetrics(storeId?: string) {
if (storeId) {
this.metrics.delete(storeId)
} else {
this.metrics.clear()
}
}
}
export const performanceAnalyzer = new StorePerformanceAnalyzer()
实践练习
练习 1:构建用户管理状态
- 创建完整的用户状态管理模块
- 实现用户信息的持久化存储
- 添加权限验证和角色管理
- 测试状态的响应性和一致性
练习 2:实现表格状态管理
- 创建可复用的表格状态管理工厂
- 实现分页、排序、筛选功能
- 添加批量操作和选择管理
- 优化数据加载和缓存策略
练习 3:开发状态同步系统
- 实现多标签页状态同步
- 添加状态持久化和恢复
- 创建状态监控和调试工具
- 测试性能和内存使用
学习资源
作业
- 完成所有实践练习
- 设计一个完整的状态管理架构
- 实现状态的性能优化方案
- 编写状态管理最佳实践文档
下一步学习计划
接下来我们将学习 Element Plus 迁移工具使用与实践,了解如何使用官方迁移工具进行版本升级和代码迁移。