【IndexedDB 】Vue2、Vue3 结合 Dexie.js 前端数据库应用与实践

【IndexedDB 】Vue2、Vue3 结合 Dexie.js 前端数据库应用与实践

前言

在现代前端开发中,本地数据存储和管理变得越来越重要。Vue3 作为主流的前端框架,结合 Dexie.js 这个轻量级的 IndexedDB 封装库,能够为应用提供强大的本地数据管理能力。本文将详细介绍如何将 Vue3 与 Dexie.js 结合使用,构建高效的前端数据库应用。

Dexie.js 简介

什么是 Dexie.js?
Dexie.js 是一个基于 IndexedDB 的轻量级包装库,提供了简洁的 API 和强大的查询能力,让前端本地数据库操作变得更加简单直观。

本版本直接内置了dexie.js文件不需要再用npm安装

一、项目结构概述(新建个配置表例子)

/database
├── dexie.js                 # Dexie.js 库文件
└── configsDB/              # 配置表数据库模块
    ├── types.js            # 数据库常量与表结构定义
    ├── Database.js         # Dexie 数据库实例创建
    ├── configsDB.js        # 配置数据库操作 API

二、核心文件解析

1. dexie.js

Dexie.js 是一个轻量级的 IndexedDB 封装库,提供了更简洁的 API 用于操作浏览器本地数据库。

主要特性:

  • 简洁的表定义语法
  • 强大的查询 API
  • Promise-based 异步操作
  • 支持版本升级
  • 事务支持

2. types.js

数据库常量与表结构定义文件。



// 数据库表结构配置
export const DB_TABLES = {
  configs: '++id, type, data, remarks, version, createdAt, updatedAt'
};

// 数据库名称
export const DB_NAME = 'ConfigureDatabase';

// 数据库版本
export const DB_VERSION = 1;

说明:

  • DB_TABLES:定义了 configs 表的结构
    • ++id:自动递增的主键
    • type:配置类型(用于分类)
    • data:配置数据内容
    • remarks:配置备注信息
    • version:配置版本号
    • createdAt:创建时间
    • updatedAt:更新时间
  • DB_NAME:数据库名称(结合环境变量动态生成)
  • DB_VERSION:数据库版本号(用于升级)

3. Database.js

Dexie 数据库实例创建文件。

import * as Dexie from '../dexie.js';
import { DB_NAME, DB_VERSION, DB_TABLES } from './types.js';

export class AppDatabase extends Dexie.default {
  constructor() {
    super(DB_NAME);
    this.version(DB_VERSION).stores(DB_TABLES);
  }
}

// 创建数据库实例
export const db = new AppDatabase();

说明:

  • 创建了 AppDatabase 类,继承自 Dexie.default
  • 在构造函数中初始化数据库名称和表结构
  • 导出 db 实例供其他模块使用

4. configsDB.js

配置数据库操作 API 文件。

import { ref, ***puted } from 'vue';
import { db } from '@/database/configsDB/Database';

export default function configDB() {
  const configs = ref([]);
  const loading = ref(false);
  const error = ref(null);

  // 获取所有配置
  const loadConfigs = async () => {
    loading.value = true;
    error.value = null;

    try {
      configs.value = await db.configs.orderBy('createdAt').reverse().toArray();
      return configs.value;
    } catch (err) {
      error.value = '加载配置失败';
      console.error('加载配置失败:', err);
    } finally {
      loading.value = false;
    }
  };

  // 添加配置
  const addConfig = async (configData) => {
    loading.value = true;
    error.value = null;

    try {
      const config = {
        ...configData,
        createdAt: new Date().toISOString().slice(0, 19).replace('T', ' '),
        updatedAt: new Date().toISOString().slice(0, 19).replace('T', ' ')
      };
      await loadConfigs(); // 重新加载列表
      const id = await db.configs.add(config);
      return id;
    } catch (err) {
      error.value = '添加配置失败';
      console.error('添加配置失败:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  // 更新配置
  const updateConfig = async (id, updates) => {
    loading.value = true;
    error.value = null;

    try {
      await db.configs.update(id, {
        ...updates,
        updatedAt: new Date().toISOString().slice(0, 19).replace('T', ' ')
      });
      await loadConfigs(); // 重新加载列表
      return "更新成功";
    } catch (err) {
      error.value = '更新配置失败';
      console.error('更新配置失败:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };

  // 删除配置
  const deleteConfig = async (id) => {
    loading.value = true;
    error.value = null;

    try {
      await db.configs.delete(id);
      await loadConfigs(); // 重新加载列表
      return "删除成功";
    } catch (err) {
      error.value = '删除配置失败';
      console.error('删除配置失败:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  };


  /**
   * 搜索配置
   * @param {string} type - 配置类型
   * @returns {Promise<Array>} - 匹配的配置数组
   * .startsWithIgnoreCase(type) - 模糊
   * .equals(type) - 精确
   */
  const searchConfigs = async (type) => {
    if (!type.trim()) {
      await loadConfigs();
      return;
    }

    loading.value = true;
    try {
      configs.value = await db.configs
        .where('type')
        .equals(type)
        .toArray();
      return configs.value;
    } catch (err) {
      error.value = '搜索配置失败';
      console.error('搜索配置失败:', err);
    } finally {
      loading.value = false;
    }
  };

  // 计算属性
  const configCount = ***puted(() => configs.value.length);
  const isEmpty = ***puted(() => configs.value.length === 0);

  return {
    // 数据
    configs,
    loading,
    error,

    // 计算属性
    configCount,
    isEmpty,

    // 方法
    loadConfigs,
    addConfig,
    updateConfig,
    deleteConfig,
    searchConfigs
  };
}

说明:

  • 基于 Vue 3 ***position API 设计
  • 提供了完整的 CRUD 操作 API
  • 包含加载状态和错误处理
  • 提供计算属性方便使用

三、使用指南

1. 初始化与引入

import configDB from '@/database/configsDB/configsDB';

const { 
  configs, loading, error,   // 响应式数据
  configCount, isEmpty,       // 计算属性
  loadConfigs, addConfig,     // 操作方法
  updateConfig, deleteConfig, 
  searchConfigs 
} = configDB();

2. 加载所有配置

async function fetchAllConfigs() {
  try {
    await loadConfigs();
    console.log('所有配置:', configs.value);
  } catch (err) {
    console.error('加载失败:', error.value);
  }
}

3. 添加配置

async function addNewConfig() {
  try {
    const configData = {
      type: 'userSettings',
      data: JSON.stringify({ theme: 'dark', fontSize: 16 }),
      remarks: '用户设置配置',
      version: 1
    };
    const id = await addConfig(configData);
    console.log('添加成功,ID:', id);
  } catch (err) {
    console.error('添加失败:', error.value);
  }
}

4. 更新配置

async function updateExistingConfig(id) {
  try {
    const updates = {
      data: JSON.stringify({ theme: 'light', fontSize: 18 }),
      version: 2
    };
    const result = await updateConfig(id, updates);
    console.log('更新成功:', result);
  } catch (err) {
    console.error('更新失败:', error.value);
  }
}

5. 删除配置

async function removeConfig(id) {
  try {
    const result = await deleteConfig(id);
    console.log('删除成功:', result);
  } catch (err) {
    console.error('删除失败:', error.value);
  }
}

6. 搜索配置

async function searchConfigsByType(type) {
  try {
    const results = await searchConfigs(type);
    console.log('搜索结果:', results);
  } catch (err) {
    console.error('搜索失败:', error.value);
  }
}

四、高级用法

1. 事务处理

Dexie.js 自动管理事务,但也可以显式创建事务:

import { db } from '@/database/configsDB/Database';

async function batchUpdate() {
  try {
    await db.transaction('rw', db.configs, async () => {
      await db.configs.update(1, { version: 3 });
      await db.configs.update(2, { version: 3 });
    });
    console.log('批量更新成功');
  } catch (err) {
    console.error('批量更新失败:', err);
  }
}

2. 版本升级

当需要修改表结构时,可以通过升级版本号来实现:

// 在 Database.js 中
class AppDatabase extends Dexie.default {
  constructor() {
    super(DB_NAME);
    this.version(1).stores(DB_TABLES);
    
    // 版本 2 升级
    this.version(2).stores({
      configs: '++id, type, data, remarks, version, createdAt, updatedAt, isActive' // 添加 isActive 字段
    });
  }
}

3. 复杂查询

async function ***plexQuery() {
  try {
    // 查询 version > 1 且 type = 'userSettings' 的配置
    const results = await db.configs
      .where('version')
      .above(1)
      .and(config => config.type === 'userSettings')
      .toArray();
    console.log('复杂查询结果:', results);
  } catch (err) {
    console.error('查询失败:', err);
  }
}

效果

五、注意事项

  1. 数据类型:

    • IndexedDB 支持存储 JavaScript 对象、数组、字符串、数字、布尔值、Date 等
    • 不支持函数、正则表达式等复杂类型
    • 建议将复杂数据 JSON.stringify() 后存储
  2. 性能优化:

    • 避免在主线程中执行大量数据操作
    • 使用索引提高查询性能
    • 合理使用事务减少 IO 操作
  3. 错误处理:

    • 始终处理异步操作的错误
    • 注意 IndexedDB 的配额限制
    • 考虑浏览器兼容性
  4. Vue 组件中使用:

    • 可以在组件的 setup() 函数中直接使用
    • 响应式数据会自动更新视图
    • 注意在组件卸载时清理资源

六、总结

本项目使用 Dexie.js 实现了一个配置数据库模块,提供了完整的 CRUD 操作 API,基于 Vue 3 ***position API 设计,方便在 Vue 组件中使用。通过合理使用 IndexedDB,可以在浏览器端实现数据持久化,提高应用的性能和用户体验。

扩展阅读:

  • Dexie.js 官方文档
  • IndexedDB 官方文档
转载请说明出处内容投诉
CSS教程网 » 【IndexedDB 】Vue2、Vue3 结合 Dexie.js 前端数据库应用与实践

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买