现代 Web 应用需要存储数据在客户端,本地存储提供了多种解决方案。
// 设置 Cookie
document.cookie = "name=John Doe; expires=Fri, 31 Dec 2023 23:59:59 GMT; path=/"
// 设置多个 Cookie
document.cookie = "userId=12345; max-age=86400; path=/; secure; samesite=strict"
document.cookie = "theme=dark; max-age=604800; path=/"
// 读取所有 Cookie
console.log(document.cookie)
// "name=John Doe; userId=12345; theme=dark"
// 解析 Cookie
function getCookie(name) {
const cookies = document.cookie.split(';')
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.trim().split('=')
if (cookieName === name) {
return decodeURIComponent(cookieValue)
}
}
return null
}
console.log(getCookie('name')) // "John Doe"
// 设置 Cookie 工具函数
function setCookie(name, value, options = {}) {
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`
if (options.expires) {
cookie += `; expires=${options.expires.toUTCString()}`
}
if (options.maxAge) {
cookie += `; max-age=${options.maxAge}`
}
if (options.path) {
cookie += `; path=${options.path}`
}
if (options.domain) {
cookie += `; domain=${options.domain}`
}
if (options.secure) {
cookie += '; secure'
}
if (options.sameSite) {
cookie += `; samesite=${options.sameSite}`
}
document.cookie = cookie
}
// 删除 Cookie
function deleteCookie(name, path = '/', domain) {
let cookie = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT`
if (path) cookie += `; path=${path}`
if (domain) cookie += `; domain=${domain}`
document.cookie = cookie
}
// 使用示例
setCookie('sessionId', 'abc123', {
maxAge: 3600, // 1小时
path: '/',
secure: true,
sameSite: 'strict'
})
console.log(getCookie('sessionId')) // "abc123"
deleteCookie('sessionId')// 检查 Cookie 是否启用
function areCookiesEnabled() {
// 尝试设置测试 Cookie
document.cookie = "testcookie=test; max-age=1"
// 检查是否设置成功
const cookiesEnabled = document.cookie.indexOf("testcookie") !== -1
// 清理测试 Cookie
document.cookie = "testcookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT"
return cookiesEnabled
}
console.log('Cookies enabled:', areCookiesEnabled())
// Cookie 大小限制(通常 4KB)
function getCookieSize() {
const cookieString = document.cookie
return new Blob([cookieString]).size
}
console.log('Cookie size:', getCookieSize(), 'bytes')
// Cookie 数量限制(通常 50-100 个)
function getCookieCount() {
return document.cookie ? document.cookie.split(';').length : 0
}
console.log('Cookie count:', getCookieCount())// 存储数据
localStorage.setItem('name', 'John Doe')
localStorage.setItem('age', '30')
localStorage.setItem('user', JSON.stringify({ id: 1, email: 'john@example.com' }))
// 读取数据
const name = localStorage.getItem('name')
const age = localStorage.getItem('age')
const user = JSON.parse(localStorage.getItem('user'))
console.log(name, age, user)
// 检查键是否存在
console.log(localStorage.hasOwnProperty('name')) // false (localStorage 不是普通对象)
console.log('name' in localStorage) // false
console.log(localStorage.getItem('name') !== null) // true
// 获取所有键
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i)
console.log(key, localStorage.getItem(key))
}
// 使用对象语法
localStorage.theme = 'dark'
console.log(localStorage.theme)
// 删除数据
localStorage.removeItem('age')
delete localStorage.theme // 也可以使用 delete
// 清空所有数据
// localStorage.clear()
// 存储复杂对象
const settings = {
theme: 'dark',
language: 'zh-CN',
notifications: {
email: true,
push: false
}
}
localStorage.setItem('settings', JSON.stringify(settings))
// 读取时需要解析
const savedSettings = JSON.parse(localStorage.getItem('settings'))
console.log(savedSettings.theme) // 'dark'// sessionStorage 的 API 与 localStorage 相同
sessionStorage.setItem('sessionId', 'abc123')
sessionStorage.setItem('lastActivity', Date.now())
console.log(sessionStorage.getItem('sessionId'))
// 页面刷新后数据仍然存在
// 关闭标签页后数据丢失
// 使用 sessionStorage 存储表单数据
function saveFormData(formId) {
const form = document.getElementById(formId)
const formData = new FormData(form)
const data = {}
for (let [key, value] of formData) {
data[key] = value
}
sessionStorage.setItem(`form_${formId}`, JSON.stringify(data))
}
function loadFormData(formId) {
const savedData = sessionStorage.getItem(`form_${formId}`)
if (savedData) {
const data = JSON.parse(savedData)
const form = document.getElementById(formId)
for (let key in data) {
const input = form.elements[key]
if (input) {
input.value = data[key]
}
}
}
}
// 自动保存表单数据
document.getElementById('myForm').addEventListener('input', () => {
saveFormData('myForm')
})
// 页面加载时恢复数据
window.addEventListener('load', () => {
loadFormData('myForm')
})// 监听存储变化
window.addEventListener('storage', (event) => {
console.log('Storage changed:')
console.log('Key:', event.key)
console.log('Old value:', event.oldValue)
console.log('New value:', event.newValue)
console.log('Storage area:', event.storageArea === localStorage ? 'localStorage' : 'sessionStorage')
console.log('URL:', event.url)
})
// 注意:storage 事件不会在设置数据的同一个页面触发
// 只会在其他标签页或窗口中触发
// 在其他窗口中修改存储
const newWindow = window.open('other-page.html')
// 在新窗口中设置数据会触发 storage 事件
setTimeout(() => {
newWindow.localStorage.setItem('sharedData', 'updated value')
}, 1000)// IndexedDB 是一个事务型数据库系统
// 特点:
// - 存储大量结构化数据
// - 异步操作
// - 支持索引
// - 支持事务
// - 同源限制
// 打开数据库
const request = indexedDB.open('MyDatabase', 1)
// 数据库版本升级
request.onupgradeneeded = function(event) {
const db = event.target.result
// 创建对象存储
if (!db.objectStoreNames.contains('users')) {
const userStore = db.createObjectStore('users', { keyPath: 'id' })
userStore.createIndex('email', 'email', { unique: true })
userStore.createIndex('name', 'name', { unique: false })
}
if (!db.objectStoreNames.contains('posts')) {
const postStore = db.createObjectStore('posts', { keyPath: 'id', autoIncrement: true })
postStore.createIndex('authorId', 'authorId', { unique: false })
postStore.createIndex('createdAt', 'createdAt', { unique: false })
}
}
request.onsuccess = function(event) {
const db = event.target.result
console.log('Database opened successfully')
// 开始使用数据库
performDatabaseOperations(db)
}
request.onerror = function(event) {
console.error('Database error:', event.target.error)
}function performDatabaseOperations(db) {
// 添加数据
function addUser(user) {
const transaction = db.transaction(['users'], 'readwrite')
const store = transaction.objectStore('users')
const request = store.add(user)
request.onsuccess = () => console.log('User added:', user.id)
request.onerror = () => console.error('Failed to add user')
}
// 查询数据
function getUser(userId) {
const transaction = db.transaction(['users'], 'readonly')
const store = transaction.objectStore('users')
const request = store.get(userId)
request.onsuccess = () => {
if (request.result) {
console.log('User found:', request.result)
} else {
console.log('User not found')
}
}
}
// 更新数据
function updateUser(user) {
const transaction = db.transaction(['users'], 'readwrite')
const store = transaction.objectStore('users')
const request = store.put(user)
request.onsuccess = () => console.log('User updated:', user.id)
request.onerror = () => console.error('Failed to update user')
}
// 删除数据
function deleteUser(userId) {
const transaction = db.transaction(['users'], 'readwrite')
const store = transaction.objectStore('users')
const request = store.delete(userId)
request.onsuccess = () => console.log('User deleted:', userId)
request.onerror = () => console.error('Failed to delete user')
}
// 查询所有数据
function getAllUsers() {
const transaction = db.transaction(['users'], 'readonly')
const store = transaction.objectStore('users')
const request = store.getAll()
request.onsuccess = () => {
console.log('All users:', request.result)
}
}
// 使用索引查询
function getUserByEmail(email) {
const transaction = db.transaction(['users'], 'readonly')
const store = transaction.objectStore('users')
const index = store.index('email')
const request = index.get(email)
request.onsuccess = () => {
console.log('User by email:', request.result)
}
}
// 使用游标遍历
function iterateUsers() {
const transaction = db.transaction(['users'], 'readonly')
const store = transaction.objectStore('users')
const request = store.openCursor()
request.onsuccess = (event) => {
const cursor = event.target.result
if (cursor) {
console.log('User:', cursor.value)
cursor.continue() // 移动到下一条记录
} else {
console.log('No more users')
}
}
}
// 使用示例
const user = { id: 1, name: 'John Doe', email: 'john@example.com' }
addUser(user)
setTimeout(() => {
getUser(1)
getAllUsers()
iterateUsers()
}, 100)
}// 将 IndexedDB 操作 Promise 化
class IndexedDBWrapper {
constructor(dbName, version) {
this.dbName = dbName
this.version = version
this.db = null
}
async open() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version)
request.onupgradeneeded = (event) => {
const db = event.target.result
this.setupSchema(db)
}
request.onsuccess = (event) => {
this.db = event.target.result
resolve(this.db)
}
request.onerror = (event) => {
reject(event.target.error)
}
})
}
setupSchema(db) {
// 子类重写此方法
throw new Error('setupSchema must be implemented by subclass')
}
async transaction(storeNames, mode = 'readonly') {
if (!this.db) {
throw new Error('Database not opened')
}
const transaction = this.db.transaction(storeNames, mode)
return transaction
}
async get(storeName, key) {
const transaction = await this.transaction([storeName])
const store = transaction.objectStore(storeName)
return new Promise((resolve, reject) => {
const request = store.get(key)
request.onsuccess = () => resolve(request.result)
request.onerror = () => reject(request.error)
})
}
async put(storeName, value) {
const transaction = await this.transaction([storeName], 'readwrite')
const store = transaction.objectStore(storeName)
return new Promise((resolve, reject) => {
const request = store.put(value)
request.onsuccess = () => resolve(request.result)
request.onerror = () => reject(request.error)
})
}
async delete(storeName, key) {
const transaction = await this.transaction([storeName], 'readwrite')
const store = transaction.objectStore(storeName)
return new Promise((resolve, reject) => {
const request = store.delete(key)
request.onsuccess = () => resolve()
request.onerror = () => reject(request.error)
})
}
}
// 使用示例
class UserDatabase extends IndexedDBWrapper {
constructor() {
super('UserDatabase', 1)
}
setupSchema(db) {
if (!db.objectStoreNames.contains('users')) {
const store = db.createObjectStore('users', { keyPath: 'id' })
store.createIndex('email', 'email', { unique: true })
}
}
}
async function demo() {
const db = new UserDatabase()
await db.open()
// 添加用户
await db.put('users', { id: 1, name: 'John', email: 'john@example.com' })
// 获取用户
const user = await db.get('users', 1)
console.log(user)
// 删除用户
await db.delete('users', 1)
}
demo()客户端存储为 Web 应用提供了丰富的数据持久化选项:
选择合适的存储方案取决于数据量、复杂度和持久化需求。