假设web项目中需要存储大量的缓存数据,通过sessionStorage和localStorage可能存在溢出,那么indexedDB就可以用用了,比如我们项目中存在多语言翻译,但是大量的翻译数据放到资源包内又不合适,需要后端接口请求的话又怕接口某次异常,导致系统bug。
统一封装一个类:
javascript
// Language/i18nDB
export default class TranslationDB {
constructor(dbName = 'TranslationDB') {
this.dbName = dbName;
this.db = null;
}
async open() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, 1); // 通过数据库名,打开indexedDB
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result; // 监听数据库链接成功,则拿到数据库实例
resolve(this);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('translations')) { // 数据库如果不存在
const store = db.createObjectStore('translations', {
keyPath: ['lang', 'key']
});
store.createIndex('by_lang', 'lang', { unique: false });// 则创建数据库
}
};
});
}
// 保存数据
async saveTranslations(lang, translations) {
if (!this.db) await this.open(); // 如果实例不存在,执行一次open
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['translations'], 'readwrite'); // 创建一个读写事务,可指定是否可读可写,还是 只是可读。
const store = transaction.objectStore('translations');// 获取对象存储区
// 清除现有数据
const clearRequest = store.index('by_lang').openCursor(IDBKeyRange.only(lang));
clearRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
cursor.delete(); // 数据删除
cursor.continue(); // 继续
} else {
// 添加新数据
const entries = Object.entries(translations);
let count = 0;
if (entries.length === 0) {
transaction.oncomplete = () => resolve();
return;
}
entries.forEach(([key, value]) => {
const request = store.put({ lang, key, value });
request.onerror = () => reject(request.error);
request.onsuccess = () => {
count++;
if (count === entries.length) {
transaction.oncomplete = () => resolve();
}
};
});
}
};
clearRequest.onerror = () => reject(clearRequest.error);
transaction.onerror = () => reject(transaction.error);
});
}
async getTranslations(lang) {
if (!this.db) await this.open();
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['translations'], 'readonly'); // 创建事务
const store = transaction.objectStore('translations');// 获取对象存储区
const index = store.index('by_lang'); // 读取数据索引
const request = index.getAll(IDBKeyRange.only(lang));// 静态方法来创建范围对象
request.onsuccess = () => {
const result = {};
request.result.forEach(item => {
result[item.key] = item.value;
});
resolve(result);
};
request.onerror = () => reject(request.error);
});
}
}
实际使用:
javascript
import { getI18nMessage } from '../../api/api'
import i18n from '@/Language';
import TranslationDB from "@/Language/i18nDB"
import _ from 'lodash'
mutations: {
SET_LANGUAGE: (state, obj) => {
i18n.mergeLocaleMessage(obj.language, obj.data)
// 待合并语言结束后,保存到本地数据库中,下次直接读取即可,无需再次请求接口获取数据
if (obj.i18nDB) {
// 保存到本地数据库中,下次直接读取即可,无需再次请求接口获取数据
obj.i18nDB.saveTranslations(obj.language, obj.data).then(res => {
console.log('多语言保存到本地数据库中')
}).catch(err => {
console.log('多语言保存到本地数据库中失败', err)
})
}
}
},
actions: {
setLanguage({ commit }, language = 'en-US') {
const i18nDB = new TranslationDB()
getI18nMessage({ language }).then(res=> { // 获取后端提供的多语言数据
const { success, data } = res
if (success && !_.isEmpty(data)) {
commit('SET_LANGUAGE', { language, data, i18nDB })
// window.localStorage.setItem(language, JSON.stringify(data))
} else {
try {
// const data = JSON.parse(window.localStorage.getItem(language))
// data && commit('SET_LANGUAGE', { language, data })
i18nDB.getTranslations(language).then(data => {
!_.isEmpty(data) && commit('SET_LANGUAGE', { language, data })
})
} catch(e) {
console.log('获取国际化失败', e)
}
}
}).catch(err => {
try {
// const data = JSON.parse(window.localStorage.getItem(language))
// data && commit('SET_LANGUAGE', { language, data })
i18nDB.getTranslations(language).then(data => {
!_.isEmpty(data) && commit('SET_LANGUAGE', { language, data })
})
} catch(e) {
console.log('获取国际化失败err', err)
}
})
}
}
javascript
// 数据示例
{
message: "成功"
success: true
timestamp: "2025-03-28 09:13:51"
url: null
data: {
App.APP_Type: "App类型:"
App.APP_Version: "App版本发布"
App.Android_Version: "安卓版本:"
App.IOS_Version: "IOS版本:"
App.New_Version: "新版本"
App.System_Config: "系统配置"
App.Whether_update: "是否强制更新:"
App.no: "否"
App.submit: "提交"
App.update_content: "更新内容描述:(用"/n"来划分)"
App.yes: "是"
}
}
indexedDB工作台展示: