Storage — 本地存储
key/value 持久化存储,数据在应用卸载前永久保存。各 Mini-App 数据相互隔离。
交互示例
Storage CRUD 操作
<script setup lang="ts">
import { ref } from 'vue'
import woo from 'mini-sdk'
const key = ref('userProfile')
const value = ref('{"name":"Alice","theme":"dark"}')
const retrieved = ref<any>(null)
const log = ref<string[]>([])
function addLog(msg: string) {
log.value.unshift(`[${new Date().toLocaleTimeString()}] ${msg}`)
if (log.value.length > 5) log.value.pop()
}
async function doSet() {
try {
const data = JSON.parse(value.value)
await woo.setStorage({ key: key.value, data })
addLog(`✅ setStorage("${key.value}") 成功`)
} catch {
await woo.setStorage({ key: key.value, data: value.value })
addLog(`✅ setStorage("${key.value}") 已存字符串`)
}
}
async function doGet() {
const res = await woo.getStorage({ key: key.value })
retrieved.value = res.data
if (res.data === null) {
addLog(`⚠️ getStorage("${key.value}") → null(key 不存在)`)
} else {
addLog(`✅ getStorage("${key.value}") 成功`)
}
}
async function doRemove() {
await woo.removeStorage({ key: key.value })
retrieved.value = null
addLog(`🗑️ removeStorage("${key.value}") 成功`)
}
async function doClear() {
await woo.clearStorage()
retrieved.value = null
addLog('🧹 clearStorage() — 所有数据已清除')
}
</script>
<template>
<div class="demo-storage">
<div class="field-row">
<div class="field">
<label>Key</label>
<input v-model="key" placeholder="key" />
</div>
<div class="field flex-1">
<label>Value (JSON 或字符串)</label>
<input v-model="value" placeholder='{"name":"Alice"}' />
</div>
</div>
<div class="btn-row">
<button class="btn btn-primary" @click="doSet">setStorage</button>
<button class="btn btn-outline" @click="doGet">getStorage</button>
<button class="btn btn-outline" @click="doRemove">removeStorage</button>
<button class="btn btn-danger" @click="doClear">clearStorage</button>
</div>
<div v-if="retrieved !== null" class="result-box">
<div class="result-label">getStorage 返回值:</div>
<pre class="result-content">{{ JSON.stringify(retrieved, null, 2) }}</pre>
</div>
<div v-if="log.length" class="log-box">
<div v-for="(entry, i) in log" :key="i" class="log-entry">{{ entry }}</div>
</div>
</div>
</template>
<style scoped>
.demo-storage { display: flex; flex-direction: column; gap: 14px; width: 100%; }
.field-row { display: flex; gap: 10px; flex-wrap: wrap; }
.field { display: flex; flex-direction: column; gap: 5px; }
.flex-1 { flex: 1; min-width: 180px; }
label { font-size: 11.5px; font-weight: 600; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.05em; }
input {
padding: 7px 10px; border-radius: 6px;
border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg);
font-size: 13px; color: var(--vp-c-text-1); font-family: var(--vp-font-family-mono);
outline: none; transition: border-color 0.15s;
}
input:focus { border-color: #6366f1; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }
.btn { padding: 7px 14px; border-radius: 6px; border: none; font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit; transition: all 0.15s; }
.btn-primary { background: #6366f1; color: white; }
.btn-primary:hover { background: #4f46e5; }
.btn-outline { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); color: var(--vp-c-text-1); }
.btn-outline:hover { background: var(--vp-c-bg-soft); }
.btn-danger { background: #fee2e2; color: #dc2626; }
.btn-danger:hover { background: #fecaca; }
.result-box { background: var(--vp-c-bg-soft); border: 1px solid var(--vp-c-divider); border-radius: 8px; padding: 12px 14px; }
.result-label { font-size: 11.5px; font-weight: 600; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 8px; }
.result-content { margin: 0; font-size: 12px; color: var(--vp-c-text-2); font-family: var(--vp-font-family-mono); white-space: pre-wrap; }
.log-box { border: 1px solid var(--vp-c-divider); border-radius: 8px; overflow: hidden; }
.log-entry { padding: 7px 12px; font-size: 12px; color: var(--vp-c-text-2); font-family: var(--vp-font-family-mono); border-bottom: 1px solid var(--vp-c-divider); }
.log-entry:last-child { border-bottom: none; }
</style>
API 参考
woo.setStorage(options)
存储数据,data 自动 JSON 序列化。ts
// 存储字符串
await woo.setStorage({ key: 'token', data: 'eyJhbGci...' })
// 存储对象(自动序列化)
await woo.setStorage({
key: 'userProfile',
data: { id: 1, name: 'Alice', avatar: 'https://...' },
})
// 存储数组
await woo.setStorage({
key: 'history',
data: ['item1', 'item2', 'item3'],
})Options
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
key | string | ✅ | 存储键名 |
data | any | ✅ | 存储数据(JSON 序列化) |
woo.getStorage<T>(options)
读取数据,key 不存在时 data 为 null。ts
// 读取字符串
const { data: token } = await woo.getStorage<string>({ key: 'token' })
if (!token) {
woo.navigateTo({ url: 'pages/login/index' })
return
}
// 读取对象(带类型推断)
interface UserProfile {
id: number
name: string
avatar: string
}
const { data: profile } = await woo.getStorage<UserProfile>({ key: 'userProfile' })
console.log(profile?.name)Options
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
key | string | ✅ | 存储键名 |
Result
| 字段 | 类型 | 说明 |
|---|---|---|
data | T | null | 存储的数据,key 不存在时为 null |
woo.removeStorage(options)
删除指定 key 的数据。ts
await woo.removeStorage({ key: 'token' })woo.clearStorage()
清空当前 Mini-App 的所有存储(不影响其他应用)。ts
// 退出登录时清空
async function logout() {
await woo.clearStorage()
await woo.reLaunch({ url: 'pages/login/index' })
}注意
clearStorage 会清空该 Mini-App 下所有 key,请慎用。
最佳实践
统一 key 命名 — 建议用常量集中管理 key,避免拼写错误:
ts
// constants/storage-keys.ts
export const StorageKey = {
TOKEN: 'auth:token',
USER_PROFILE: 'user:profile',
SETTINGS: 'app:settings',
} as const带过期时间 — Storage 本身不支持 TTL,可封装实现:
ts
async function setWithExpiry(key: string, value: any, ttlMs: number) {
await woo.setStorage({
key,
data: { value, expiry: Date.now() + ttlMs },
})
}
async function getWithExpiry<T>(key: string): Promise<T | null> {
const { data } = await woo.getStorage<{ value: T; expiry: number }>({ key })
if (!data || Date.now() > data.expiry) {
await woo.removeStorage({ key })
return null
}
return data.value
}