【indexedDB】以web端多语言存储为例

假设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工作台展示:

相关推荐
旭久6 分钟前
react+antd封装一个可回车自定义option的select并且与某些内容相互禁用
前端·javascript·react.js
是纽扣也是烤奶10 分钟前
关于React Redux
前端
阿丽塔~13 分钟前
React 函数组件间怎么进行通信?
前端·javascript·react.js
冴羽37 分钟前
SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照
前端·javascript·svelte
uhakadotcom38 分钟前
Langflow:打造AI应用的强大工具
前端·面试·github
前端小张同学1 小时前
AI编程-cursor无限使用, 还有谁不会🎁🎁🎁??
前端·cursor
yanxy5121 小时前
【TS学习】(15)分布式条件特性
前端·学习·typescript
uhakadotcom1 小时前
Caddy Web服务器初体验:简洁高效的现代选择
前端·面试·github
前端菜鸟来报道1 小时前
前端react 实现分段进度条
前端·javascript·react.js·进度条