当前位置: 首页 > news >正文

Vue 中使用 Dexie.js

Dexie.js 是一个优秀的 IndexedDB 封装库,结合 Vue 可以轻松实现客户端数据存储。

1. 安装与初始化

安装 Dexie.js

npm install dexie
# 或
yarn add dexie

创建数据库服务文件

在 src 目录下创建 db.js 文件:

import Dexie from 'dexie';const db = new Dexie('VueDatabase');// 定义数据库结构
db.version(1).stores({todos: '++id, title, completed, createdAt',notes: '++id, content, tags, updatedAt'
});// 可选:添加示例数据
db.on('populate', () => {db.todos.add({ title: '学习Dexie.js', completed: false, createdAt: new Date() });db.notes.add({ content: '这是我的第一条笔记', tags: ['重要'], updatedAt: new Date() });
});export default db;

2. 在 Vue 组件中使用

基本 CRUD 操作

<template><div><h2>待办事项</h2><input v-model="newTodo" @keyup.enter="addTodo" placeholder="添加新任务"><ul><li v-for="todo in todos" :key="todo.id"><input type="checkbox" v-model="todo.completed" @change="updateTodo(todo)"><span :class="{ completed: todo.completed }">{{ todo.title }}</span><button @click="deleteTodo(todo.id)">删除</button></li></ul></div>
</template><script>
import db from '@/db';export default {data() {return {todos: [],newTodo: ''};},async created() {await this.loadTodos();},methods: {async loadTodos() {this.todos = await db.todos.toArray();},async addTodo() {if (!this.newTodo.trim()) return;await db.todos.add({title: this.newTodo,completed: false,createdAt: new Date()});this.newTodo = '';await this.loadTodos();},async updateTodo(todo) {await db.todos.update(todo.id, {completed: todo.completed});},async deleteTodo(id) {await db.todos.delete(id);await this.loadTodos();}}
};
</script><style>
.completed {text-decoration: line-through;color: #888;
}
</style>

3. 使用 Vue 插件形式

为了在整个应用中更方便地使用数据库,可以创建 Vue 插件:

创建插件 src/plugins/dexie.js

import Dexie from 'dexie';const VueDexie = {install(Vue) {const db = new Dexie('VueAppDB');db.version(1).stores({settings: '++id, key, value',userData: '++id, userId, data'});Vue.prototype.$db = db;}
};export default VueDexie;

在 main.js 中注册插件

import Vue from 'vue';
import App from './App.vue';
import DexiePlugin from './plugins/dexie';Vue.use(DexiePlugin);new Vue({render: h => h(App)
}).$mount('#app');

在组件中使用

<script>
export default {async mounted() {// 使用插件提供的 $dbconst settings = await this.$db.settings.toArray();console.log(settings);// 添加设置await this.$db.settings.add({key: 'theme',value: 'dark'});}
};
</script>

4. 高级用法

响应式数据绑定

<template><div><h2>笔记列表</h2><div v-for="note in notes" :key="note.id"><h3>{{ note.content }}</h3><p>标签: {{ note.tags.join(', ') }}</p></div></div>
</template><script>
import { liveQuery } from 'dexie';
import db from '@/db';export default {data() {return {notes: []};},created() {// 使用 liveQuery 实现响应式数据this.subscription = liveQuery(() => db.notes.orderBy('updatedAt').reverse().toArray()).subscribe({next: notes => {this.notes = notes;},error: error => {console.error('查询错误:', error);}});},beforeDestroy() {// 组件销毁时取消订阅this.subscription && this.subscription.unsubscribe();}
};
</script>

复杂查询与分页

async function getPaginatedNotes(page = 1, pageSize = 10) {const offset = (page - 1) * pageSize;return await db.notes.orderBy('updatedAt').reverse().offset(offset).limit(pageSize).toArray();
}// 在组件中使用
export default {methods: {async loadNotes(page) {this.notes = await getPaginatedNotes(page);}}
};

事务处理

async function transferData(fromId, toId, amount) {await db.transaction('rw', db.userData, async () => {const fromUser = await db.userData.get(fromId);const toUser = await db.userData.get(toId);if (!fromUser || !toUser) {throw new Error('用户不存在');}if (fromUser.data.balance < amount) {throw new Error('余额不足');}await db.userData.update(fromId, {'data.balance': fromUser.data.balance - amount});await db.userData.update(toId, {'data.balance': toUser.data.balance + amount});});
}

5. 最佳实践

  1. 错误处理:始终处理数据库操作的错误

    try {await db.someTable.add(data);
    } catch (error) {console.error('操作失败:', error);this.$toast.error('保存失败');
    }
  2. 性能优化

    • 批量操作使用 bulkAddbulkPutbulkDelete

    • 大量数据时使用分页

    • 合理创建索引

  3. 数据同步

    // 与后端API同步的示例
    async function syncTodos() {const localTodos = await db.todos.toArray();const serverTodos = await api.getTodos();// 比较并合并数据的逻辑...
    }

     4.数据库升级处理

    db.version(2).stores({todos: '++id, title, completed, createdAt, priority',notes: '++id, content, tags, updatedAt, isPinned'
    }).upgrade(tx => {return tx.table('todos').toCollection().modify(todo => {todo.priority = todo.priority || 'normal';});
    });

    6. 完整示例:Todo 应用

    <template><div class="todo-app"><h1>Vue Dexie Todo</h1><div class="todo-form"><inputv-model="newTodo"@keyup.enter="addTodo"placeholder="输入任务并回车"><select v-model="priority"><option value="low">低优先级</option><option value="normal">普通</option><option value="high">高优先级</option></select><button @click="addTodo">添加</button></div><div class="filters"><button @click="filter = 'all'">全部</button><button @click="filter = 'active'">未完成</button><button @click="filter = 'completed'">已完成</button></div><ul class="todo-list"><li v-for="todo in filteredTodos" :key="todo.id" :class="{completed: todo.completed,'high-priority': todo.priority === 'high','low-priority': todo.priority === 'low'}"><inputtype="checkbox"v-model="todo.completed"@change="updateTodo(todo)"><span class="todo-title">{{ todo.title }}</span><span class="todo-date">{{ formatDate(todo.createdAt) }}</span><button @click="deleteTodo(todo.id)">删除</button></li></ul><div class="stats"><span>总计: {{ todos.length }} | 剩余: {{ activeCount }}</span><button v-if="completedCount > 0" @click="clearCompleted">清除已完成</button></div></div>
    </template><script>
    import db from '@/db';
    import { liveQuery } from 'dexie';export default {data() {return {todos: [],newTodo: '',priority: 'normal',filter: 'all'};},created() {this.subscription = liveQuery(() => db.todos.orderBy('createdAt').toArray()).subscribe({next: todos => {this.todos = todos;},error: error => {console.error('加载待办事项失败:', error);}});},computed: {filteredTodos() {switch (this.filter) {case 'active':return this.todos.filter(t => !t.completed);case 'completed':return this.todos.filter(t => t.completed);default:return this.todos;}},activeCount() {return this.todos.filter(t => !t.completed).length;},completedCount() {return this.todos.filter(t => t.completed).length;}},methods: {formatDate(date) {return new Date(date).toLocaleDateString();},async addTodo() {if (!this.newTodo.trim()) return;try {await db.todos.add({title: this.newTodo,completed: false,priority: this.priority,createdAt: new Date()});this.newTodo = '';} catch (error) {console.error('添加任务失败:', error);}},async updateTodo(todo) {try {await db.todos.update(todo.id, {completed: todo.completed});} catch (error) {console.error('更新任务失败:', error);}},async deleteTodo(id) {try {await db.todos.delete(id);} catch (error) {console.error('删除任务失败:', error);}},async clearCompleted() {try {const completedIds = this.todos.filter(t => t.completed).map(t => t.id);await db.todos.bulkDelete(completedIds);} catch (error) {console.error('清除已完成任务失败:', error);}}},beforeDestroy() {this.subscription && this.subscription.unsubscribe();}
    };
    </script><style>
    .todo-app {max-width: 600px;margin: 0 auto;padding: 20px;
    }.todo-form {display: flex;margin-bottom: 20px;
    }.todo-form input {flex-grow: 1;padding: 8px;margin-right: 10px;
    }.filters {margin-bottom: 20px;
    }.todo-list {list-style: none;padding: 0;
    }.todo-list li {display: flex;align-items: center;padding: 10px;border-bottom: 1px solid #eee;
    }.todo-title {flex-grow: 1;margin: 0 10px;
    }.todo-date {font-size: 0.8em;color: #888;margin-right: 10px;
    }.completed .todo-title {text-decoration: line-through;color: #888;
    }.high-priority {border-left: 3px solid red;padding-left: 7px;
    }.low-priority {opacity: 0.7;
    }.stats {margin-top: 20px;display: flex;justify-content: space-between;align-items: center;
    }
    </style>

7. 总结

在 Vue 中使用 Dexie.js 的关键点:

  1. 将数据库初始化代码封装为单独模块

  2. 使用 liveQuery 实现响应式数据绑定

  3. 合理处理异步操作和错误

  4. 在组件销毁时取消订阅

  5. 对于复杂应用,考虑使用 Vuex/Pinia 管理状态

Dexie.js 与 Vue 的结合可以轻松实现离线优先的应用程序,提供良好的用户体验。

 

http://www.dtcms.com/a/307549.html

相关文章:

  • 城市客运安全员证考试难不难?如何高效备考
  • CUDA系列之常用Runtime API简介
  • BatchNorm 一般放在哪里?
  • Ⅹ—6.计算机二级综合题19---22套
  • 接口自动化测试以及requests
  • TS语法最佳实践
  • 【笔记】热力学定律推导(6)热力学第二定律推导
  • 【MATLAB】(二)基础知识
  • Golang 指针
  • Valgrind终极指南:深入内存安全与性能瓶颈检测
  • 云原生运维与混合云运维:如何选择及 Wisdom SSH 的应用
  • Android依赖注入框架Hilt入门指南
  • 大白话畅谈:stm32中断和FreeRTOS的中断
  • 【源力觉醒 创作者计划】_巅峰对话文心 4.5 与通义千问、DeepSeek 能力对比解析
  • 【工具】NVM完全指南:Node.js版本管理工具的安装与使用详解
  • 如何将照片从 realme 手机传输到电脑?
  • MongoDB系列教程-第四章:MongoDB Compass可视化和管理MongoDB数据库
  • node.js之Koa框架
  • 蓝牙 BR/EDR 与 BLE PHY
  • Kafka在Springboot项目中的实践
  • vue3.0 + TypeScript 中使用 axios 同时进行二次封装
  • ESXI虚拟交换机 + H3C S5120交换机 + GR5200路由器组网笔记
  • 数据结构与算法:队列的表示和操作的实现
  • Linux 下自动化脚本安装Jdk、Nginx等软件
  • Java语言/Netty框架的新能源汽车充电桩系统平台
  • 《人工智能导论》(python版)第2章 python基础2.2编程基础
  • Rust视频处理开源项目精选
  • FFmpegHandler 功能解析,C语言程序化设计与C++面向对象设计的核心差异
  • 【日常问题解决方案】VS2022不小心解决方案资源管理器把关掉了怎么办
  • spring cloud alibaba ——gateway网关