本课程将深入讲解UniApp中的数据存储机制,包括本地存储API、数据加密、存储最佳实践以及云开发数据库操作。掌握数据存储技术对于构建功能完整的应用至关重要。
UniApp提供了完整的本地存储API,支持异步和同步两种方式。本地存储数据会永久保存,除非用户手动清除应用数据。
异步API不会阻塞主线程,适合存储大量数据或在关键路径上使用。
// 存储数据
uni.setStorage({
key: 'userInfo',
data: {
id: 1,
name: '张三',
age: 25
},
success: function () {
console.log('数据存储成功')
},
fail: function (error) {
console.error('存储失败', error)
}
})
// 获取数据
uni.getStorage({
key: 'userInfo',
success: function (res) {
console.log('获取到的数据', res.data)
},
fail: function (error) {
console.error('获取失败', error)
}
})
// 移除数据
uni.removeStorage({
key: 'userInfo',
success: function () {
console.log('数据移除成功')
}
})
// 清空所有数据
uni.clearStorage({
success: function () {
console.log('所有数据已清空')
}
})
// 获取存储信息
uni.getStorageInfo({
success: function (res) {
console.log('当前存储信息', res)
// res.keys: 当前storage中所有的key
// res.currentSize: 当前占用的空间大小, 单位kb
// res.limitSize: 限制的空间大小, 单位kb
}
})
同步API会阻塞主线程,使用时需要注意性能影响,适合存储少量数据或在非关键路径上使用。
// 同步存储数据
try {
uni.setStorageSync('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9')
console.log('数据存储成功')
} catch (e) {
console.error('存储失败', e)
}
// 同步获取数据
try {
const token = uni.getStorageSync('token')
console.log('获取到的token', token)
} catch (e) {
console.error('获取失败', e)
}
// 同步移除数据
try {
uni.removeStorageSync('token')
console.log('数据移除成功')
} catch (e) {
console.error('移除失败', e)
}
// 同步清空所有数据
try {
uni.clearStorageSync()
console.log('所有数据已清空')
} catch (e) {
console.error('清空失败', e)
}
// 同步获取存储信息
try {
const info = uni.getStorageInfoSync()
console.log('当前存储信息', info)
} catch (e) {
console.error('获取信息失败', e)
}
UniApp的本地存储支持多种数据类型,但实际存储时都会被转换为字符串。
// 存储字符串
uni.setStorageSync('username', 'admin')
// 存储数字
uni.setStorageSync('age', 25)
// 存储布尔值
uni.setStorageSync('isLogin', true)
// 存储对象(会被自动JSON序列化)
uni.setStorageSync('user', {
id: 1,
name: '张三',
avatar: 'https://example.com/avatar.jpg'
})
// 存储数组
uni.setStorageSync('cart', [
{ id: 1, name: '商品1', price: 99 },
{ id: 2, name: '商品2', price: 199 }
])
// 存储null和undefined
uni.setStorageSync('empty', null)
uni.setStorageSync('undefined', undefined)
对于敏感数据(如用户token、个人信息等),建议进行加密存储,提高数据安全性。
// utils/crypto.js
import CryptoJS from 'crypto-js'
const SECRET_KEY = 'your-secret-key-32-characters'
export function encrypt(data) {
const jsonString = JSON.stringify(data)
const encrypted = CryptoJS.AES.encrypt(jsonString, SECRET_KEY).toString()
return encrypted
}
export function decrypt(encryptedData) {
try {
const bytes = CryptoJS.AES.decrypt(encryptedData, SECRET_KEY)
const decryptedString = bytes.toString(CryptoJS.enc.Utf8)
return JSON.parse(decryptedString)
} catch (e) {
console.error('解密失败', e)
return null
}
}
export function setSecureStorage(key, data) {
const encrypted = encrypt(data)
uni.setStorageSync(key, encrypted)
}
export function getSecureStorage(key) {
const encrypted = uni.getStorageSync(key)
if (!encrypted) return null
return decrypt(encrypted)
}
export function removeSecureStorage(key) {
uni.removeStorageSync(key)
}
// 使用加密存储
import { setSecureStorage, getSecureStorage, removeSecureStorage } from '@/utils/crypto'
// 存储敏感数据
setSecureStorage('userInfo', {
id: 1,
name: '张三',
phone: '13800138000',
idCard: '110101199001011234'
})
// 获取敏感数据
const userInfo = getSecureStorage('userInfo')
console.log(userInfo)
// 移除敏感数据
removeSecureStorage('userInfo')
为了方便使用,可以封装一个统一的存储工具类。
// utils/storage.js
class Storage {
constructor(prefix = 'app_') {
this.prefix = prefix
}
getKey(key) {
return this.prefix + key
}
set(key, value, expire = null) {
const data = {
value: value,
time: Date.now()
}
if (expire) {
data.expire = Date.now() + expire * 1000
}
uni.setStorageSync(this.getKey(key), data)
}
get(key) {
const data = uni.getStorageSync(this.getKey(key))
if (!data) return null
if (data.expire && Date.now() > data.expire) {
this.remove(key)
return null
}
return data.value
}
remove(key) {
uni.removeStorageSync(this.getKey(key))
}
clear() {
const info = uni.getStorageInfoSync()
info.keys.forEach(key => {
if (key.startsWith(this.prefix)) {
uni.removeStorageSync(key)
}
})
}
setWithExpire(key, value, seconds) {
this.set(key, value, seconds)
}
has(key) {
return uni.getStorageSync(this.getKey(key)) !== ''
}
getAll() {
const info = uni.getStorageInfoSync()
const result = {}
info.keys.forEach(key => {
if (key.startsWith(this.prefix)) {
const originalKey = key.replace(this.prefix, '')
result[originalKey] = this.get(originalKey)
}
})
return result
}
}
export default new Storage('uniapp_')
// 使用封装的存储工具
import storage from '@/utils/storage'
// 存储数据
storage.set('username', 'admin')
storage.set('userInfo', { id: 1, name: '张三' })
// 存储带过期时间的数据(10秒后过期)
storage.setWithExpire('tempData', { code: '123456' }, 10)
// 获取数据
const username = storage.get('username')
const userInfo = storage.get('userInfo')
// 检查数据是否存在
if (storage.has('userInfo')) {
console.log('用户信息存在')
}
// 移除数据
storage.remove('username')
// 获取所有数据
const allData = storage.getAll()
// 清空所有数据
storage.clear()
如果使用UniApp云开发,可以使用云数据库进行数据存储。云数据库支持丰富的查询操作和实时数据同步。
// 初始化云开发
const db = uniCloud.database()
// 获取集合引用
const usersCollection = db.collection('users')
const ordersCollection = db.collection('orders')
// 添加数据
async function addUser() {
try {
const res = await usersCollection.add({
name: '张三',
age: 25,
email: 'zhangsan@example.com',
createTime: db.serverDate()
})
console.log('添加成功', res.id)
} catch (e) {
console.error('添加失败', e)
}
}
// 查询数据
async function getUsers() {
try {
const res = await usersCollection.where({
age: db.command.gte(18)
}).get()
console.log('查询结果', res.data)
} catch (e) {
console.error('查询失败', e)
}
}
// 更新数据
async function updateUser(userId) {
try {
const res = await usersCollection.doc(userId).update({
age: 26,
updateTime: db.serverDate()
})
console.log('更新成功', res.updated)
} catch (e) {
console.error('更新失败', e)
}
}
// 删除数据
async function deleteUser(userId) {
try {
const res = await usersCollection.doc(userId).remove()
console.log('删除成功', res.deleted)
} catch (e) {
console.error('删除失败', e)
}
}
// 条件查询
const res = await usersCollection.where({
age: db.command.gte(18).and(db.command.lte(30)),
name: db.command.eq('张三')
}).get()
// 模糊查询
const res = await usersCollection.where({
name: db.command.like('张%')
}).get()
// 排序
const res = await usersCollection.where({
age: db.command.gte(18)
}).orderBy('createTime', 'desc')
.limit(10)
.skip(0)
.get()
// 字段过滤
const res = await usersCollection.field({
name: true,
age: true,
_id: true
}).get()
// 统计查询
const res = await usersCollection.where({
age: db.command.gte(18)
}).count()
console.log('符合条件的用户数', res.total)
// store/user.js
import storage from '@/utils/storage'
const USER_KEY = 'user_info'
const TOKEN_KEY = 'access_token'
export default {
namespaced: true,
state: {
userInfo: null,
token: null
},
mutations: {
SET_USER(state, userInfo) {
state.userInfo = userInfo
storage.set(USER_KEY, userInfo)
},
SET_TOKEN(state, token) {
state.token = token
storage.set(TOKEN_KEY, token)
},
CLEAR_USER(state) {
state.userInfo = null
state.token = null
storage.remove(USER_KEY)
storage.remove(TOKEN_KEY)
}
},
actions: {
init({ commit }) {
const userInfo = storage.get(USER_KEY)
const token = storage.get(TOKEN_KEY)
if (userInfo && token) {
commit('SET_USER', userInfo)
commit('SET_TOKEN', token)
}
},
login({ commit }, { userInfo, token }) {
commit('SET_USER', userInfo)
commit('SET_TOKEN', token)
},
logout({ commit }) {
commit('CLEAR_USER')
}
},
getters: {
isLogin: state => !!state.token,
userId: state => state.userInfo?.id,
userName: state => state.userInfo?.name
}
}
// utils/cart.js
import storage from '@/utils/storage'
const CART_KEY = 'shopping_cart'
export default {
getCart() {
return storage.get(CART_KEY) || []
},
addToCart(product) {
const cart = this.getCart()
const existingItem = cart.find(item => item.id === product.id)
if (existingItem) {
existingItem.quantity += product.quantity || 1
} else {
cart.push({
id: product.id,
name: product.name,
price: product.price,
image: product.image,
quantity: product.quantity || 1
})
}
storage.set(CART_KEY, cart)
return cart
},
removeFromCart(productId) {
let cart = this.getCart()
cart = cart.filter(item => item.id !== productId)
storage.set(CART_KEY, cart)
return cart
},
updateQuantity(productId, quantity) {
const cart = this.getCart()
const item = cart.find(item => item.id === productId)
if (item) {
item.quantity = quantity
if (item.quantity <= 0) {
return this.removeFromCart(productId)
}
storage.set(CART_KEY, cart)
}
return cart
},
clearCart() {
storage.remove(CART_KEY)
return []
},
getCartTotal() {
const cart = this.getCart()
return cart.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
},
getCartCount() {
const cart = this.getCart()
return cart.reduce((count, item) => {
return count + item.quantity
}, 0)
}
}
// utils/search.js
import storage from '@/utils/storage'
const HISTORY_KEY = 'search_history'
const MAX_HISTORY = 10
export default {
getHistory() {
return storage.get(HISTORY_KEY) || []
},
addHistory(keyword) {
if (!keyword || keyword.trim() === '') return
let history = this.getHistory()
history = history.filter(item => item !== keyword)
history.unshift(keyword)
if (history.length > MAX_HISTORY) {
history = history.slice(0, MAX_HISTORY)
}
storage.set(HISTORY_KEY, history)
return history
},
removeHistory(keyword) {
let history = this.getHistory()
history = history.filter(item => item !== keyword)
storage.set(HISTORY_KEY, history)
return history
},
clearHistory() {
storage.remove(HISTORY_KEY)
return []
}
}
A: 本地存储的数据在应用更新后仍然存在,除非用户手动清除应用数据或卸载应用。
A: 可以通过uni.getStorageInfo获取存储信息,当空间不足时提示用户清理数据或使用云存储。
A: 本地存储适合存储用户配置、缓存数据等;云数据库适合存储需要同步、共享的业务数据。
A: 可以结合本地存储和云数据库,本地作为缓存,云端作为数据源,定期同步数据。
本课程详细讲解了UniApp中的数据存储机制,包括:
掌握数据存储技术后,你可以在应用中实现用户状态管理、数据缓存、离线功能等重要特性。下一课我们将学习组件通信的相关知识。