1. Vuex状态管理
1.1 Vuex基础配置
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import app from './modules/app'
import cart from './modules/cart'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
// 全局状态
version: '1.0.0',
platform: '',
networkType: 'unknown'
},
mutations: {
SET_PLATFORM(state, platform) {
state.platform = platform
},
SET_NETWORK_TYPE(state, networkType) {
state.networkType = networkType
}
},
actions: {
// 初始化应用
async initApp({ commit, dispatch }) {
try {
// 获取系统信息
const systemInfo = await uni.getSystemInfo()
commit('SET_PLATFORM', systemInfo.platform)
// 获取网络信息
const networkInfo = await uni.getNetworkType()
commit('SET_NETWORK_TYPE', networkInfo.networkType)
// 初始化用户信息
await dispatch('user/initUser')
// 初始化应用设置
await dispatch('app/initSettings')
console.log('应用初始化完成')
} catch (error) {
console.error('应用初始化失败:', error)
}
}
},
getters: {
// 全局计算属性
isOnline: state => state.networkType !== 'none',
isMobile: state => ['android', 'ios'].includes(state.platform)
},
modules: {
user,
app,
cart
},
// 开发环境启用严格模式
strict: process.env.NODE_ENV !== 'production'
})
export default store
1.2 用户模块
// store/modules/user.js
const state = {
userInfo: null,
token: '',
isLoggedIn: false,
permissions: [],
profile: {
avatar: '',
nickname: '',
phone: '',
email: ''
}
}
const mutations = {
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo
state.isLoggedIn = !!userInfo
},
SET_TOKEN(state, token) {
state.token = token
// 同步到本地存储
if (token) {
uni.setStorageSync('token', token)
} else {
uni.removeStorageSync('token')
}
},
SET_PERMISSIONS(state, permissions) {
state.permissions = permissions
},
UPDATE_PROFILE(state, profile) {
state.profile = { ...state.profile, ...profile }
},
CLEAR_USER_DATA(state) {
state.userInfo = null
state.token = ''
state.isLoggedIn = false
state.permissions = []
state.profile = {
avatar: '',
nickname: '',
phone: '',
email: ''
}
}
}
const actions = {
// 初始化用户
async initUser({ commit, dispatch }) {
try {
const token = uni.getStorageSync('token')
if (token) {
commit('SET_TOKEN', token)
await dispatch('getUserInfo')
}
} catch (error) {
console.error('初始化用户失败:', error)
}
},
// 用户登录
async login({ commit, dispatch }, { username, password }) {
try {
// 模拟登录API
const response = await loginAPI({ username, password })
const { token, userInfo } = response
// 保存token和用户信息
commit('SET_TOKEN', token)
commit('SET_USER_INFO', userInfo)
// 获取用户权限
await dispatch('getUserPermissions')
// 保存用户信息到本地
uni.setStorageSync('userInfo', userInfo)
return response
} catch (error) {
console.error('登录失败:', error)
throw error
}
},
// 用户注册
async register({ commit }, userData) {
try {
const response = await registerAPI(userData)
return response
} catch (error) {
console.error('注册失败:', error)
throw error
}
},
// 获取用户信息
async getUserInfo({ commit, state }) {
try {
if (!state.token) {
throw new Error('未登录')
}
const userInfo = await getUserInfoAPI()
commit('SET_USER_INFO', userInfo)
// 保存到本地存储
uni.setStorageSync('userInfo', userInfo)
return userInfo
} catch (error) {
console.error('获取用户信息失败:', error)
// 如果token无效,清除用户数据
if (error.code === 401) {
commit('CLEAR_USER_DATA')
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
}
throw error
}
},
// 获取用户权限
async getUserPermissions({ commit, state }) {
try {
if (!state.token) {
return
}
const permissions = await getUserPermissionsAPI()
commit('SET_PERMISSIONS', permissions)
return permissions
} catch (error) {
console.error('获取用户权限失败:', error)
}
},
// 更新用户资料
async updateProfile({ commit, dispatch }, profileData) {
try {
const updatedProfile = await updateProfileAPI(profileData)
commit('UPDATE_PROFILE', updatedProfile)
// 重新获取用户信息
await dispatch('getUserInfo')
return updatedProfile
} catch (error) {
console.error('更新用户资料失败:', error)
throw error
}
},
// 修改密码
async changePassword({ state }, { oldPassword, newPassword }) {
try {
const response = await changePasswordAPI({
oldPassword,
newPassword
})
uni.showToast({
title: '密码修改成功',
icon: 'success'
})
return response
} catch (error) {
console.error('修改密码失败:', error)
throw error
}
},
// 用户登出
async logout({ commit }) {
try {
// 调用登出API
await logoutAPI()
} catch (error) {
console.error('登出API调用失败:', error)
} finally {
// 无论API是否成功,都清除本地数据
commit('CLEAR_USER_DATA')
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
// 跳转到登录页
uni.reLaunch({
url: '/pages/login/login'
})
}
}
}
const getters = {
// 是否已登录
isLoggedIn: state => state.isLoggedIn,
// 用户ID
userId: state => state.userInfo?.id,
// 用户昵称
nickname: state => state.userInfo?.nickname || state.profile.nickname || '未设置',
// 用户头像
avatar: state => state.userInfo?.avatar || state.profile.avatar || '/static/default-avatar.png',
// 是否有特定权限
hasPermission: state => permission => {
return state.permissions.includes(permission)
},
// 是否是VIP用户
isVip: state => state.userInfo?.vip || false,
// 用户等级
userLevel: state => state.userInfo?.level || 1
}
// 模拟API函数
function loginAPI(credentials) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (credentials.username === 'admin' && credentials.password === '123456') {
resolve({
token: 'mock-token-' + Date.now(),
userInfo: {
id: 1,
username: 'admin',
nickname: '管理员',
avatar: '/static/avatar.png',
phone: '13800138000',
email: 'admin@example.com',
vip: true,
level: 5
}
})
} else {
reject(new Error('用户名或密码错误'))
}
}, 1000)
})
}
function registerAPI(userData) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ success: true, message: '注册成功' })
}, 1000)
})
}
function getUserInfoAPI() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
id: 1,
username: 'admin',
nickname: '管理员',
avatar: '/static/avatar.png',
phone: '13800138000',
email: 'admin@example.com',
vip: true,
level: 5
})
}, 500)
})
}
function getUserPermissionsAPI() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(['read', 'write', 'delete', 'admin'])
}, 500)
})
}
function updateProfileAPI(profileData) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(profileData)
}, 1000)
})
}
function changePasswordAPI(passwordData) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ success: true })
}, 1000)
})
}
function logoutAPI() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ success: true })
}, 500)
})
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
1.3 应用设置模块
// store/modules/app.js
const state = {
theme: 'light', // light, dark, auto
language: 'zh-CN',
fontSize: 'medium', // small, medium, large
notifications: {
push: true,
sound: true,
vibrate: true
},
cache: {
images: true,
data: true,
maxSize: 100 // MB
},
privacy: {
analytics: true,
location: false,
camera: false
}
}
const mutations = {
SET_THEME(state, theme) {
state.theme = theme
uni.setStorageSync('app_theme', theme)
},
SET_LANGUAGE(state, language) {
state.language = language
uni.setStorageSync('app_language', language)
},
SET_FONT_SIZE(state, fontSize) {
state.fontSize = fontSize
uni.setStorageSync('app_fontSize', fontSize)
},
UPDATE_NOTIFICATIONS(state, notifications) {
state.notifications = { ...state.notifications, ...notifications }
uni.setStorageSync('app_notifications', state.notifications)
},
UPDATE_CACHE_SETTINGS(state, cache) {
state.cache = { ...state.cache, ...cache }
uni.setStorageSync('app_cache', state.cache)
},
UPDATE_PRIVACY_SETTINGS(state, privacy) {
state.privacy = { ...state.privacy, ...privacy }
uni.setStorageSync('app_privacy', state.privacy)
},
RESET_SETTINGS(state) {
state.theme = 'light'
state.language = 'zh-CN'
state.fontSize = 'medium'
state.notifications = {
push: true,
sound: true,
vibrate: true
}
state.cache = {
images: true,
data: true,
maxSize: 100
}
state.privacy = {
analytics: true,
location: false,
camera: false
}
}
}
const actions = {
// 初始化设置
async initSettings({ commit }) {
try {
// 从本地存储加载设置
const theme = uni.getStorageSync('app_theme') || 'light'
const language = uni.getStorageSync('app_language') || 'zh-CN'
const fontSize = uni.getStorageSync('app_fontSize') || 'medium'
const notifications = uni.getStorageSync('app_notifications') || {
push: true,
sound: true,
vibrate: true
}
const cache = uni.getStorageSync('app_cache') || {
images: true,
data: true,
maxSize: 100
}
const privacy = uni.getStorageSync('app_privacy') || {
analytics: true,
location: false,
camera: false
}
commit('SET_THEME', theme)
commit('SET_LANGUAGE', language)
commit('SET_FONT_SIZE', fontSize)
commit('UPDATE_NOTIFICATIONS', notifications)
commit('UPDATE_CACHE_SETTINGS', cache)
commit('UPDATE_PRIVACY_SETTINGS', privacy)
// 应用主题
await this.dispatch('app/applyTheme', theme)
console.log('应用设置初始化完成')
} catch (error) {
console.error('初始化设置失败:', error)
}
},
// 应用主题
async applyTheme({ state }, theme) {
try {
// 设置状态栏样式
if (theme === 'dark') {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#1a1a1a'
})
} else {
uni.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#ffffff'
})
}
// 通知其他组件主题变化
uni.$emit('themeChange', theme)
console.log('主题应用成功:', theme)
} catch (error) {
console.error('应用主题失败:', error)
}
},
// 切换主题
async toggleTheme({ commit, dispatch, state }) {
const newTheme = state.theme === 'light' ? 'dark' : 'light'
commit('SET_THEME', newTheme)
await dispatch('applyTheme', newTheme)
},
// 清除缓存
async clearCache({ state }) {
try {
if (state.cache.images) {
// 清除图片缓存
console.log('清除图片缓存')
}
if (state.cache.data) {
// 清除数据缓存
const keys = uni.getStorageInfoSync().keys
const cacheKeys = keys.filter(key => key.startsWith('cache_'))
cacheKeys.forEach(key => {
uni.removeStorageSync(key)
})
console.log('清除数据缓存')
}
uni.showToast({
title: '缓存清除成功',
icon: 'success'
})
} catch (error) {
console.error('清除缓存失败:', error)
uni.showToast({
title: '清除缓存失败',
icon: 'none'
})
}
},
// 重置所有设置
async resetAllSettings({ commit, dispatch }) {
try {
commit('RESET_SETTINGS')
// 清除本地存储的设置
uni.removeStorageSync('app_theme')
uni.removeStorageSync('app_language')
uni.removeStorageSync('app_fontSize')
uni.removeStorageSync('app_notifications')
uni.removeStorageSync('app_cache')
uni.removeStorageSync('app_privacy')
// 重新应用默认主题
await dispatch('applyTheme', 'light')
uni.showToast({
title: '设置已重置',
icon: 'success'
})
} catch (error) {
console.error('重置设置失败:', error)
}
}
}
const getters = {
// 是否是深色主题
isDarkTheme: state => state.theme === 'dark',
// 是否启用推送通知
isPushEnabled: state => state.notifications.push,
// 字体大小样式
fontSizeClass: state => {
const sizeMap = {
small: 'font-small',
medium: 'font-medium',
large: 'font-large'
}
return sizeMap[state.fontSize] || 'font-medium'
},
// 缓存设置摘要
cacheSummary: state => {
const enabled = []
if (state.cache.images) enabled.push('图片')
if (state.cache.data) enabled.push('数据')
return enabled.length > 0 ? enabled.join('、') + '缓存已启用' : '缓存已禁用'
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
1.4 购物车模块
// store/modules/cart.js
const state = {
items: [],
selectedItems: [],
coupon: null,
shippingAddress: null
}
const mutations = {
ADD_TO_CART(state, product) {
const existingItem = state.items.find(item => item.id === product.id)
if (existingItem) {
existingItem.quantity += product.quantity || 1
} else {
state.items.push({
...product,
quantity: product.quantity || 1,
addedAt: Date.now()
})
}
// 保存到本地存储
uni.setStorageSync('cart_items', state.items)
},
REMOVE_FROM_CART(state, productId) {
state.items = state.items.filter(item => item.id !== productId)
state.selectedItems = state.selectedItems.filter(id => id !== productId)
// 保存到本地存储
uni.setStorageSync('cart_items', state.items)
},
UPDATE_QUANTITY(state, { productId, quantity }) {
const item = state.items.find(item => item.id === productId)
if (item) {
if (quantity <= 0) {
// 数量为0时移除商品
state.items = state.items.filter(item => item.id !== productId)
state.selectedItems = state.selectedItems.filter(id => id !== productId)
} else {
item.quantity = quantity
}
}
// 保存到本地存储
uni.setStorageSync('cart_items', state.items)
},
SET_SELECTED_ITEMS(state, selectedItems) {
state.selectedItems = selectedItems
},
TOGGLE_ITEM_SELECTION(state, productId) {
const index = state.selectedItems.indexOf(productId)
if (index > -1) {
state.selectedItems.splice(index, 1)
} else {
state.selectedItems.push(productId)
}
},
SELECT_ALL_ITEMS(state) {
state.selectedItems = state.items.map(item => item.id)
},
CLEAR_SELECTION(state) {
state.selectedItems = []
},
SET_COUPON(state, coupon) {
state.coupon = coupon
},
SET_SHIPPING_ADDRESS(state, address) {
state.shippingAddress = address
uni.setStorageSync('shipping_address', address)
},
CLEAR_CART(state) {
state.items = []
state.selectedItems = []
state.coupon = null
// 清除本地存储
uni.removeStorageSync('cart_items')
},
LOAD_CART_FROM_STORAGE(state) {
const items = uni.getStorageSync('cart_items') || []
const address = uni.getStorageSync('shipping_address') || null
state.items = items
state.shippingAddress = address
}
}
const actions = {
// 初始化购物车
initCart({ commit }) {
commit('LOAD_CART_FROM_STORAGE')
},
// 添加到购物车
addToCart({ commit }, product) {
commit('ADD_TO_CART', product)
uni.showToast({
title: '已添加到购物车',
icon: 'success'
})
},
// 批量添加到购物车
addMultipleToCart({ commit }, products) {
products.forEach(product => {
commit('ADD_TO_CART', product)
})
uni.showToast({
title: `已添加${products.length}件商品`,
icon: 'success'
})
},
// 从购物车移除
removeFromCart({ commit }, productId) {
commit('REMOVE_FROM_CART', productId)
uni.showToast({
title: '已从购物车移除',
icon: 'success'
})
},
// 批量移除
removeSelectedItems({ commit, state }) {
state.selectedItems.forEach(productId => {
commit('REMOVE_FROM_CART', productId)
})
commit('CLEAR_SELECTION')
uni.showToast({
title: '已移除选中商品',
icon: 'success'
})
},
// 更新商品数量
updateQuantity({ commit }, { productId, quantity }) {
commit('UPDATE_QUANTITY', { productId, quantity })
},
// 应用优惠券
async applyCoupon({ commit }, couponCode) {
try {
// 模拟验证优惠券
const coupon = await validateCouponAPI(couponCode)
commit('SET_COUPON', coupon)
uni.showToast({
title: '优惠券应用成功',
icon: 'success'
})
return coupon
} catch (error) {
uni.showToast({
title: error.message || '优惠券无效',
icon: 'none'
})
throw error
}
},
// 移除优惠券
removeCoupon({ commit }) {
commit('SET_COUPON', null)
uni.showToast({
title: '已移除优惠券',
icon: 'success'
})
},
// 设置收货地址
setShippingAddress({ commit }, address) {
commit('SET_SHIPPING_ADDRESS', address)
},
// 创建订单
async createOrder({ commit, state, getters }) {
try {
if (state.selectedItems.length === 0) {
throw new Error('请选择要购买的商品')
}
if (!state.shippingAddress) {
throw new Error('请设置收货地址')
}
const orderData = {
items: getters.selectedItemsDetail,
totalAmount: getters.selectedItemsTotal,
coupon: state.coupon,
shippingAddress: state.shippingAddress,
createdAt: Date.now()
}
// 调用创建订单API
const order = await createOrderAPI(orderData)
// 清除已购买的商品
state.selectedItems.forEach(productId => {
commit('REMOVE_FROM_CART', productId)
})
commit('CLEAR_SELECTION')
commit('SET_COUPON', null)
uni.showToast({
title: '订单创建成功',
icon: 'success'
})
return order
} catch (error) {
console.error('创建订单失败:', error)
uni.showToast({
title: error.message || '创建订单失败',
icon: 'none'
})
throw error
}
}
}
const getters = {
// 购物车商品总数
totalItems: state => {
return state.items.reduce((total, item) => total + item.quantity, 0)
},
// 购物车总金额
totalAmount: state => {
return state.items.reduce((total, item) => {
return total + (item.price * item.quantity)
}, 0)
},
// 选中商品详情
selectedItemsDetail: state => {
return state.items.filter(item => state.selectedItems.includes(item.id))
},
// 选中商品总数
selectedItemsCount: (state, getters) => {
return getters.selectedItemsDetail.reduce((total, item) => total + item.quantity, 0)
},
// 选中商品总金额
selectedItemsTotal: (state, getters) => {
return getters.selectedItemsDetail.reduce((total, item) => {
return total + (item.price * item.quantity)
}, 0)
},
// 优惠金额
discountAmount: (state, getters) => {
if (!state.coupon) return 0
const total = getters.selectedItemsTotal
if (state.coupon.type === 'percentage') {
return total * (state.coupon.value / 100)
} else if (state.coupon.type === 'fixed') {
return Math.min(state.coupon.value, total)
}
return 0
},
// 最终支付金额
finalAmount: (state, getters) => {
return Math.max(0, getters.selectedItemsTotal - getters.discountAmount)
},
// 是否全选
isAllSelected: state => {
return state.items.length > 0 && state.selectedItems.length === state.items.length
},
// 购物车是否为空
isEmpty: state => state.items.length === 0
}
// 模拟API函数
function validateCouponAPI(couponCode) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const validCoupons = {
'SAVE10': { code: 'SAVE10', type: 'percentage', value: 10, name: '9折优惠券' },
'SAVE50': { code: 'SAVE50', type: 'fixed', value: 50, name: '满减50元' }
}
if (validCoupons[couponCode]) {
resolve(validCoupons[couponCode])
} else {
reject(new Error('优惠券不存在或已过期'))
}
}, 1000)
})
}
function createOrderAPI(orderData) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
id: 'ORDER_' + Date.now(),
...orderData,
status: 'pending'
})
}, 1500)
})
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
2. 本地存储
2.1 存储工具类
// utils/storage.js
class Storage {
constructor(prefix = 'app_') {
this.prefix = prefix
}
// 生成完整的key
getKey(key) {
return this.prefix + key
}
// 设置存储(同步)
set(key, value, options = {}) {
try {
const data = {
value,
timestamp: Date.now(),
expire: options.expire ? Date.now() + options.expire : null,
version: options.version || '1.0.0'
}
uni.setStorageSync(this.getKey(key), data)
return true
} catch (error) {
console.error('存储设置失败:', error)
return false
}
}
// 获取存储(同步)
get(key, defaultValue = null) {
try {
const data = uni.getStorageSync(this.getKey(key))
if (!data) {
return defaultValue
}
// 检查是否过期
if (data.expire && Date.now() > data.expire) {
this.remove(key)
return defaultValue
}
return data.value
} catch (error) {
console.error('存储获取失败:', error)
return defaultValue
}
}
// 设置存储(异步)
setAsync(key, value, options = {}) {
return new Promise((resolve, reject) => {
try {
const data = {
value,
timestamp: Date.now(),
expire: options.expire ? Date.now() + options.expire : null,
version: options.version || '1.0.0'
}
uni.setStorage({
key: this.getKey(key),
data,
success: () => resolve(true),
fail: reject
})
} catch (error) {
reject(error)
}
})
}
// 获取存储(异步)
getAsync(key, defaultValue = null) {
return new Promise((resolve) => {
uni.getStorage({
key: this.getKey(key),
success: (res) => {
const data = res.data
if (!data) {
resolve(defaultValue)
return
}
// 检查是否过期
if (data.expire && Date.now() > data.expire) {
this.remove(key)
resolve(defaultValue)
return
}
resolve(data.value)
},
fail: () => resolve(defaultValue)
})
})
}
// 删除存储
remove(key) {
try {
uni.removeStorageSync(this.getKey(key))
return true
} catch (error) {
console.error('存储删除失败:', error)
return false
}
}
// 删除存储(异步)
removeAsync(key) {
return new Promise((resolve, reject) => {
uni.removeStorage({
key: this.getKey(key),
success: () => resolve(true),
fail: reject
})
})
}
// 清空所有存储
clear() {
try {
const info = uni.getStorageInfoSync()
const keys = info.keys.filter(key => key.startsWith(this.prefix))
keys.forEach(key => {
uni.removeStorageSync(key)
})
return true
} catch (error) {
console.error('清空存储失败:', error)
return false
}
}
// 获取存储信息
getInfo() {
try {
const info = uni.getStorageInfoSync()
const appKeys = info.keys.filter(key => key.startsWith(this.prefix))
return {
keys: appKeys,
currentSize: info.currentSize,
limitSize: info.limitSize,
usage: info.currentSize / info.limitSize
}
} catch (error) {
console.error('获取存储信息失败:', error)
return null
}
}
// 检查key是否存在
has(key) {
try {
const data = uni.getStorageSync(this.getKey(key))
if (!data) {
return false
}
// 检查是否过期
if (data.expire && Date.now() > data.expire) {
this.remove(key)
return false
}
return true
} catch (error) {
return false
}
}
// 获取所有keys
keys() {
try {
const info = uni.getStorageInfoSync()
return info.keys
.filter(key => key.startsWith(this.prefix))
.map(key => key.replace(this.prefix, ''))
} catch (error) {
console.error('获取keys失败:', error)
return []
}
}
// 批量设置
setBatch(data, options = {}) {
const results = []
for (const [key, value] of Object.entries(data)) {
const result = this.set(key, value, options)
results.push({ key, success: result })
}
return results
}
// 批量获取
getBatch(keys, defaultValue = null) {
const results = {}
keys.forEach(key => {
results[key] = this.get(key, defaultValue)
})
return results
}
// 批量删除
removeBatch(keys) {
const results = []
keys.forEach(key => {
const result = this.remove(key)
results.push({ key, success: result })
})
return results
}
}
// 创建默认实例
const storage = new Storage('app_')
// 创建特定用途的存储实例
const userStorage = new Storage('user_')
const cacheStorage = new Storage('cache_')
const configStorage = new Storage('config_')
export default storage
export { Storage, userStorage, cacheStorage, configStorage }
2.2 缓存管理
// utils/cache.js
import { cacheStorage } from './storage.js'
class CacheManager {
constructor() {
this.storage = cacheStorage
this.defaultExpire = 30 * 60 * 1000 // 30分钟
this.maxCacheSize = 50 * 1024 * 1024 // 50MB
}
// 设置缓存
set(key, data, expire = this.defaultExpire) {
try {
const cacheData = {
data,
timestamp: Date.now(),
expire: Date.now() + expire,
size: JSON.stringify(data).length
}
// 检查缓存大小
this.checkCacheSize()
return this.storage.set(key, cacheData)
} catch (error) {
console.error('设置缓存失败:', error)
return false
}
}
// 获取缓存
get(key, defaultValue = null) {
try {
const cacheData = this.storage.get(key)
if (!cacheData) {
return defaultValue
}
// 检查是否过期
if (Date.now() > cacheData.expire) {
this.storage.remove(key)
return defaultValue
}
return cacheData.data
} catch (error) {
console.error('获取缓存失败:', error)
return defaultValue
}
}
// 删除缓存
remove(key) {
return this.storage.remove(key)
}
// 清空所有缓存
clear() {
return this.storage.clear()
}
// 检查缓存是否存在且未过期
has(key) {
const cacheData = this.storage.get(key)
if (!cacheData) {
return false
}
if (Date.now() > cacheData.expire) {
this.storage.remove(key)
return false
}
return true
}
// 获取或设置缓存(如果不存在则执行函数并缓存结果)
async getOrSet(key, asyncFunction, expire = this.defaultExpire) {
// 先尝试从缓存获取
const cached = this.get(key)
if (cached !== null) {
return cached
}
try {
// 执行异步函数获取数据
const data = await asyncFunction()
// 缓存结果
this.set(key, data, expire)
return data
} catch (error) {
console.error('获取数据失败:', error)
throw error
}
}
// 检查缓存大小并清理
checkCacheSize() {
try {
const info = this.storage.getInfo()
if (info && info.currentSize > this.maxCacheSize) {
this.cleanupOldCache()
}
} catch (error) {
console.error('检查缓存大小失败:', error)
}
}
// 清理旧缓存
cleanupOldCache() {
try {
const keys = this.storage.keys()
const cacheItems = []
// 收集所有缓存项的信息
keys.forEach(key => {
const cacheData = this.storage.get(key)
if (cacheData && cacheData.timestamp) {
cacheItems.push({
key,
timestamp: cacheData.timestamp,
size: cacheData.size || 0
})
}
})
// 按时间排序,删除最旧的缓存
cacheItems.sort((a, b) => a.timestamp - b.timestamp)
// 删除前30%的旧缓存
const deleteCount = Math.floor(cacheItems.length * 0.3)
for (let i = 0; i < deleteCount; i++) {
this.storage.remove(cacheItems[i].key)
}
console.log(`清理了${deleteCount}个旧缓存`)
} catch (error) {
console.error('清理旧缓存失败:', error)
}
}
// 获取缓存统计信息
getStats() {
try {
const keys = this.storage.keys()
let totalSize = 0
let expiredCount = 0
let validCount = 0
keys.forEach(key => {
const cacheData = this.storage.get(key)
if (cacheData) {
totalSize += cacheData.size || 0
if (Date.now() > cacheData.expire) {
expiredCount++
} else {
validCount++
}
}
})
return {
totalKeys: keys.length,
validCount,
expiredCount,
totalSize,
formattedSize: this.formatSize(totalSize)
}
} catch (error) {
console.error('获取缓存统计失败:', error)
return null
}
}
// 格式化大小
formatSize(bytes) {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
// 清理过期缓存
cleanupExpired() {
try {
const keys = this.storage.keys()
let cleanedCount = 0
keys.forEach(key => {
const cacheData = this.storage.get(key)
if (cacheData && Date.now() > cacheData.expire) {
this.storage.remove(key)
cleanedCount++
}
})
console.log(`清理了${cleanedCount}个过期缓存`)
return cleanedCount
} catch (error) {
console.error('清理过期缓存失败:', error)
return 0
}
}
}
// 创建缓存管理实例
const cache = new CacheManager()
export default cache
export { CacheManager }
3. 数据持久化
3.1 数据库操作(SQLite)
// utils/database.js
class Database {
constructor() {
this.dbName = 'app.db'
this.dbVersion = '1.0'
this.db = null
}
// 初始化数据库
async init() {
try {
// 注意:UniApp中SQLite需要使用插件
// 这里提供一个通用的接口设计
// 创建表
await this.createTables()
console.log('数据库初始化成功')
} catch (error) {
console.error('数据库初始化失败:', error)
throw error
}
}
// 创建表
async createTables() {
const tables = [
{
name: 'users',
sql: `
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT,
avatar TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`
},
{
name: 'settings',
sql: `
CREATE TABLE IF NOT EXISTS settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
value TEXT,
type TEXT DEFAULT 'string',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`
},
{
name: 'cache_data',
sql: `
CREATE TABLE IF NOT EXISTS cache_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
data TEXT,
expire_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`
}
]
for (const table of tables) {
await this.executeSql(table.sql)
}
}
// 执行SQL
async executeSql(sql, params = []) {
// 这里需要根据实际使用的SQLite插件来实现
// 例如使用 uni-sqlite 插件
return new Promise((resolve, reject) => {
// 模拟SQL执行
setTimeout(() => {
console.log('执行SQL:', sql, params)
resolve({ success: true })
}, 100)
})
}
// 查询数据
async select(table, conditions = {}, options = {}) {
try {
let sql = `SELECT * FROM ${table}`
const params = []
// 构建WHERE条件
if (Object.keys(conditions).length > 0) {
const whereClause = Object.keys(conditions)
.map(key => {
params.push(conditions[key])
return `${key} = ?`
})
.join(' AND ')
sql += ` WHERE ${whereClause}`
}
// 添加排序
if (options.orderBy) {
sql += ` ORDER BY ${options.orderBy}`
if (options.order) {
sql += ` ${options.order}`
}
}
// 添加限制
if (options.limit) {
sql += ` LIMIT ${options.limit}`
if (options.offset) {
sql += ` OFFSET ${options.offset}`
}
}
const result = await this.executeSql(sql, params)
return result.rows || []
} catch (error) {
console.error('查询数据失败:', error)
throw error
}
}
// 插入数据
async insert(table, data) {
try {
const keys = Object.keys(data)
const values = Object.values(data)
const placeholders = keys.map(() => '?').join(', ')
const sql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES (${placeholders})`
const result = await this.executeSql(sql, values)
return result.insertId
} catch (error) {
console.error('插入数据失败:', error)
throw error
}
}
// 更新数据
async update(table, data, conditions) {
try {
const setClause = Object.keys(data)
.map(key => `${key} = ?`)
.join(', ')
const whereClause = Object.keys(conditions)
.map(key => `${key} = ?`)
.join(' AND ')
const sql = `UPDATE ${table} SET ${setClause} WHERE ${whereClause}`
const params = [...Object.values(data), ...Object.values(conditions)]
const result = await this.executeSql(sql, params)
return result.rowsAffected
} catch (error) {
console.error('更新数据失败:', error)
throw error
}
}
// 删除数据
async delete(table, conditions) {
try {
const whereClause = Object.keys(conditions)
.map(key => `${key} = ?`)
.join(' AND ')
const sql = `DELETE FROM ${table} WHERE ${whereClause}`
const params = Object.values(conditions)
const result = await this.executeSql(sql, params)
return result.rowsAffected
} catch (error) {
console.error('删除数据失败:', error)
throw error
}
}
// 清空表
async truncate(table) {
try {
const sql = `DELETE FROM ${table}`
await this.executeSql(sql)
return true
} catch (error) {
console.error('清空表失败:', error)
throw error
}
}
// 关闭数据库
async close() {
try {
// 关闭数据库连接
console.log('数据库连接已关闭')
} catch (error) {
console.error('关闭数据库失败:', error)
}
}
}
// 创建数据库实例
const database = new Database()
export default database
export { Database }
3.2 数据同步
// utils/sync.js
import storage from './storage.js'
import cache from './cache.js'
class DataSync {
constructor() {
this.syncQueue = []
this.isOnline = true
this.syncInterval = 30000 // 30秒
this.maxRetries = 3
this.init()
}
// 初始化
init() {
// 监听网络状态
uni.onNetworkStatusChange((res) => {
this.isOnline = res.isConnected
if (this.isOnline) {
console.log('网络已连接,开始同步数据')
this.syncPendingData()
} else {
console.log('网络已断开,数据将缓存到本地')
}
})
// 定期同步
setInterval(() => {
if (this.isOnline) {
this.syncPendingData()
}
}, this.syncInterval)
// 应用启动时同步
this.loadPendingSync()
}
// 添加到同步队列
addToSyncQueue(action, data, options = {}) {
const syncItem = {
id: Date.now() + Math.random(),
action,
data,
timestamp: Date.now(),
retries: 0,
maxRetries: options.maxRetries || this.maxRetries,
priority: options.priority || 'normal' // high, normal, low
}
this.syncQueue.push(syncItem)
this.savePendingSync()
// 如果在线,立即尝试同步
if (this.isOnline) {
this.syncPendingData()
}
return syncItem.id
}
// 同步待处理数据
async syncPendingData() {
if (this.syncQueue.length === 0) {
return
}
console.log(`开始同步${this.syncQueue.length}条数据`)
// 按优先级排序
this.syncQueue.sort((a, b) => {
const priorityOrder = { high: 3, normal: 2, low: 1 }
return priorityOrder[b.priority] - priorityOrder[a.priority]
})
const syncPromises = this.syncQueue.map(item => this.syncSingleItem(item))
try {
await Promise.allSettled(syncPromises)
// 移除已成功同步的项目
this.syncQueue = this.syncQueue.filter(item => item.retries < item.maxRetries)
this.savePendingSync()
console.log('数据同步完成')
} catch (error) {
console.error('数据同步失败:', error)
}
}
// 同步单个项目
async syncSingleItem(item) {
try {
let result
switch (item.action) {
case 'create':
result = await this.syncCreate(item.data)
break
case 'update':
result = await this.syncUpdate(item.data)
break
case 'delete':
result = await this.syncDelete(item.data)
break
default:
throw new Error(`未知的同步操作: ${item.action}`)
}
console.log(`同步成功: ${item.action}`, result)
// 从队列中移除
const index = this.syncQueue.findIndex(queueItem => queueItem.id === item.id)
if (index > -1) {
this.syncQueue.splice(index, 1)
}
return result
} catch (error) {
console.error(`同步失败: ${item.action}`, error)
// 增加重试次数
item.retries++
if (item.retries >= item.maxRetries) {
console.error(`同步项目达到最大重试次数,将被移除:`, item)
// 记录失败的同步项目
this.recordFailedSync(item, error)
}
throw error
}
}
// 同步创建操作
async syncCreate(data) {
// 模拟API调用
const response = await fetch('/api/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${storage.get('token')}`
},
body: JSON.stringify(data)
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
}
// 同步更新操作
async syncUpdate(data) {
const response = await fetch(`/api/update/${data.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${storage.get('token')}`
},
body: JSON.stringify(data)
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
}
// 同步删除操作
async syncDelete(data) {
const response = await fetch(`/api/delete/${data.id}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${storage.get('token')}`
}
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
}
// 保存待同步数据
savePendingSync() {
storage.set('pending_sync', this.syncQueue)
}
// 加载待同步数据
loadPendingSync() {
const pendingSync = storage.get('pending_sync', [])
this.syncQueue = pendingSync
}
// 记录失败的同步项目
recordFailedSync(item, error) {
const failedSyncs = storage.get('failed_syncs', [])
failedSyncs.push({
...item,
error: error.message,
failedAt: Date.now()
})
// 只保留最近100条失败记录
if (failedSyncs.length > 100) {
failedSyncs.splice(0, failedSyncs.length - 100)
}
storage.set('failed_syncs', failedSyncs)
}
// 获取同步状态
getSyncStatus() {
return {
isOnline: this.isOnline,
pendingCount: this.syncQueue.length,
failedCount: storage.get('failed_syncs', []).length,
lastSyncTime: storage.get('last_sync_time')
}
}
// 手动触发同步
async forcSync() {
if (!this.isOnline) {
throw new Error('网络未连接,无法同步')
}
await this.syncPendingData()
storage.set('last_sync_time', Date.now())
}
// 清除失败的同步记录
clearFailedSyncs() {
storage.remove('failed_syncs')
}
}
// 创建数据同步实例
const dataSync = new DataSync()
export default dataSync
export { DataSync }
4. 状态管理最佳实践
4.1 模块化设计
// store/index.js - 主store配置
import Vue from 'vue'
import Vuex from 'vuex'
// 导入所有模块
import user from './modules/user'
import app from './modules/app'
import cart from './modules/cart'
import product from './modules/product'
import order from './modules/order'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user,
app,
cart,
product,
order
},
// 全局状态
state: {
loading: false,
error: null
},
// 全局mutations
mutations: {
SET_LOADING(state, loading) {
state.loading = loading
},
SET_ERROR(state, error) {
state.error = error
},
CLEAR_ERROR(state) {
state.error = null
}
},
// 全局actions
actions: {
// 显示加载状态
showLoading({ commit }, message = '加载中...') {
commit('SET_LOADING', true)
uni.showLoading({ title: message })
},
// 隐藏加载状态
hideLoading({ commit }) {
commit('SET_LOADING', false)
uni.hideLoading()
},
// 显示错误信息
showError({ commit }, error) {
commit('SET_ERROR', error)
uni.showToast({
title: error.message || '操作失败',
icon: 'none'
})
},
// 清除错误
clearError({ commit }) {
commit('CLEAR_ERROR')
}
},
// 全局getters
getters: {
isLoading: state => state.loading,
hasError: state => !!state.error,
errorMessage: state => state.error?.message || ''
}
})
export default store
4.2 状态持久化插件
// plugins/persist.js
const persistPlugin = (store) => {
// 需要持久化的模块
const persistModules = ['user', 'app', 'cart']
// 从本地存储恢复状态
const savedState = uni.getStorageSync('vuex_state')
if (savedState) {
store.replaceState({
...store.state,
...savedState
})
}
// 监听状态变化并保存
store.subscribe((mutation, state) => {
// 只保存指定模块的状态
const persistState = {}
persistModules.forEach(module => {
if (state[module]) {
persistState[module] = state[module]
}
})
uni.setStorageSync('vuex_state', persistState)
})
}
export default persistPlugin
4.3 使用示例
<!-- pages/profile/profile.vue -->
<template>
<view class="profile-page">
<view class="user-info" v-if="isLoggedIn">
<image :src="avatar" class="avatar"></image>
<text class="nickname">{{ nickname }}</text>
<text class="level">等级: {{ userLevel }}</text>
</view>
<view class="login-prompt" v-else>
<button @click="goToLogin">请先登录</button>
</view>
<view class="settings">
<view class="setting-item" @click="toggleTheme">
<text>深色模式</text>
<switch :checked="isDarkTheme" @change="toggleTheme"></switch>
</view>
<view class="setting-item">
<text>字体大小</text>
<picker :value="fontSizeIndex" :range="fontSizes" @change="changeFontSize">
<text>{{ currentFontSize }}</text>
</picker>
</view>
</view>
<view class="cache-info">
<text>缓存状态: {{ cacheSummary }}</text>
<button @click="clearCache">清除缓存</button>
</view>
</view>
</template>
<script>
import { mapState, mapGetters, mapActions } from 'vuex'
export default {
data() {
return {
fontSizes: ['小', '中', '大'],
fontSizeIndex: 1
}
},
computed: {
...mapState('user', ['userInfo']),
...mapGetters('user', ['isLoggedIn', 'nickname', 'avatar', 'userLevel']),
...mapGetters('app', ['isDarkTheme', 'fontSizeClass', 'cacheSummary']),
currentFontSize() {
return this.fontSizes[this.fontSizeIndex]
}
},
methods: {
...mapActions('user', ['logout']),
...mapActions('app', ['toggleTheme', 'clearCache']),
goToLogin() {
uni.navigateTo({
url: '/pages/login/login'
})
},
changeFontSize(e) {
this.fontSizeIndex = e.detail.value
const fontSize = ['small', 'medium', 'large'][this.fontSizeIndex]
this.$store.commit('app/SET_FONT_SIZE', fontSize)
}
},
onLoad() {
// 页面加载时的逻辑
}
}
</script>
5. 总结
状态管理与数据存储是UniApp应用的重要组成部分:
- Vuex状态管理:提供集中式的状态管理,便于组件间数据共享
- 本地存储:使用uni.storage API进行数据持久化
- 缓存管理:实现智能缓存策略,提升应用性能
- 数据同步:处理离线数据和在线同步
- 最佳实践:模块化设计、状态持久化、合理的数据流