dexie.js中⽂教程
dexie.js使⽤教程
what 它是什么
dexie.js是⼀个对浏览器indexexDB的包装库,使得我们可以更⽅便地操作indexedDB。
why 为什么⽤它
由于原⽣indexedDB具有⼏下缺点
原⽣所有操作都是在回调中进⾏的
原⽣所有操作都需要不断地创建事务,判断表和索引的存在性
原⽣为表建⽴索引很繁琐
原⽣查询⽀持的较为简单,复杂的查询需要⾃⼰去实现
原⽣不⽀持批量操作
原⽣的错误需要在每个失败回调中接收处理
基于此,出现了很多对原⽣接⼝的包装,⽽相⽐于其它包装库,dexie.js具有以下明显的优点:
⼏乎所有接⼝都返回promise,即符合indexedDB异步操作的特性,对开发者⼜直观友好,可以使⽤promise链,错误可以在catch中统⼀处理,且有丰富的错误类型返回。
即⽀持与原⽣⼀致的接⼝,⽐如open、get、put、add、delete、transcation等等,⼜⽀持扩展的⾮常丰富的更加便捷的接⼝,
如。
类似于后端数据库的⾼级查询,并且⽀持链式调⽤,如官⽅⽰例:
db.friends.where('shoeSize')
.between(37,40)
.or('name')
.anyOf(['Arnold','Ingemar'])
.and(function(friend){return friend.isCloseFriend;})
.limit(10)
.each(function(friend){
console.log(JSON.stringify(friend));
});
更丰富的索引定义,建⽴索引变得⾮常简单,并且⽀持多值索引和复合索引
db.version(1).stores({
users:"++id, name, &username, *email, address.city",
relations:"++, userId1, userId2, [userId1+userId2], relation"
});
接近原⽣的性能。
丰富完善的⽂档,虽然⽬前只有英⽂⽂档,但也是所有indexedDB包装库中⽂档最为完善的了。
how 怎么⽤
在使⽤此库之前,最好能够系统的了解和简单使⽤原⽣indexedDB,可参阅 或我写的
获取数据库实例
获取⼀个数据库实例
var db =new Dexie(dbname);
dbname:数据库的名称
这⾥只是获得数据库实例,与传⼊的数据库是否已经存在没有关系,如果已经存在,就会返回已经存在的数据库的⼀个⽰例,如果不存在,就会新建⼀个数据库,并返回该数据库的⼀个实例。
定义数据库结构
db.version(lastVersion).stores(
{
localVersions:'matadataid, content, lastversionid, date, time',
users:"++id, name, &username, *email, address.city",
relations:"++rid, userId1, userId2, [userId1+userId2], relation",
books:'id, author, name, *categories'
}
);
lastVersion : 当前数据库最新版本,只有需要修改数据库结构时才更改这个值。
由于dexiejs需要兼容IE的⼀个BUG,所以在实际建库的时候版本号都会乘以10,如果这⾥lastVersion传0.1,实际建的库的版本就是1
上例中的localVersions,users,relations 都是数据库要包含的objectStore的名称,⽽他们的值则是要定义的索引,如果某个字段不需要索引,则不要写⼊这个索引列表,另外,如果某个字段存储的是图⽚数据(imageData),视频(arrayBuffer),或者特别⼤的字符串,不建议加⼊索引列表。
可以定义四种索引:
主键(⾃增):索引列表的第⼀个总会被当做主键,如上例中的matadataid,id,rid,如果主键前有++ 符号,说明这个字段是⾃增的。
唯⼀索引。如果某个索引的字段的值在所有记录中是唯⼀的,那么可以在它前⾯加& 号,⽐如上例中users仓库中的username字段。
多值索引。 如果某个字段具有多个值,那么可以在它前⾯加*号将其设置为多值索引,如上例中的books仓库中的categories字段,⽤户可以根据它多个值的任何⼀个值来查询它,如:
db.books.put({
id:1,
name:'Under the Dome',
author:'Stephen King',
categories:['sci-fi','thriller']
});
这⾥⾯的categores 是个数组,有多个值,那么我们就可以将其设置为多值索引
然后我们查询时便可以⽤其中⼀个值为查询条件去查询:
function getSciFiBooks(){
return db.books
.where('categories').equals('sci-fi')
.toArray();
}
这⾥便会查询到所有类型为sci-fi 的书籍,即使这些书还可能同时属于其他分类。
复合索引。如果某个索引是基于多个键路径的,就可以将其设置为复合索引,格式为[A+B],如上例中relations中
的[userId1+userId2] 索引。下⾯是⼀个例⼦:
// Store relations
lations.put({
rid:1,
rid:1,
userId1:'1',
userId2:'2'
});
// Query relations:
const fooBar =lations.where({
userId1:'1',
userId2:'2'
}).first();
当你定义了复合索引后,就可以在where查询⼦句中传⼊⼀个复合条件对象,该⽰例就将查询出userId1为1,userId2为2的记录,但同时,你也可以只以其中⼀个字段为索引条件进⾏查询:
.where('userId1')
.equals("1")
.toArray();
每次页⾯刷新都会重新获取⼀遍实例,重新运⾏⼀遍数据库定义逻辑,不会有问题吗?
答案是,不会有问题。如果你传⼊的lastVersion与数据库当前版本⼀致,则即使重新运⾏⼀遍数据库定义逻辑,也不会覆盖你第⼀次运⾏时定义的结构(即使你修改了数据库结构),在这种情况下,你已经存⼊的数据不会受任何影响。只有当lastVersion版本⾼于当前数据库版本时,才会去更新数据库结构(即使结构没有任何变化),这时如果定义中的仓库被删除了,那对应的仓库会被删除,如果定义中是索引被删除了,那仓库中对应的索引也会被删除。
【只有执⾏完version().stores()⽅法之后再⾄少进⾏⼀次数据库操作(⽐如open(), get(),put()等),这个才可以⽣效,因
为versions().store()只是定义结构,并不⽴即⽣效,⽽是等到进⾏数据库操作时才会打开数据库进⾏更新】
在具体的实践中,建议将获取数据库实例和定义表结构的代码封装在⼀起,然后返回⼀个单例,整个应⽤中需要这个数据库的地⽅都从这个⽅法获取这个单例,这样可以保证所有对数据库结构的改动都在⼀个地⽅进⾏,从⽽保证数据库版本的⼀致。
官⽅的vue版本TODO应⽤的⽰例如下:
import Dexie from'dexie';
export class Database extends Dexie {
constructor(){
super('database');
this.version(1).stores({
todos:'++id,done',
});
}
async getTodos(order){
let todos =[];
switch(order){
case forwardOrder:
todos =derBy('id').toArray();
break;
case reverseOrder:
todos =derBy('id').reverse().toArray();
break;
case unfinishedFirstOrder:
todos =derBy('done').toArray();
break;
default:
// as a default just fall back to forward order
todos =derBy('id').toArray();
}
return todos.map((t)=>{
t.done =!!t.done;
return t;
});
}
setTodoDone(id, done){
dos.update(id,{ done: done ?1:0})
}
addTodo(text){
// add a todo by passing in an object using Table.add. dos.add({ text: text, done:0})
}
deleteTodo(todoID){
// delete a todo by passing in the ID of that todo.
dos.delete(todoID);
}
}
export const forwardOrder ='forward';
export const reverseOrder ='reverse';
export const unfinishedFirstOrder ='unfinished-first';
// App.vue
<template>
<div class="app">
<div class="app-header">
<h2>Vue + Dexie Todo Example</h2>
</div>
<AddTodo @add-todo="addTodo" />
:todos="todos"
@toggle-todo="toggleTodo"
@delete-todo="deleteTodo"
@sort-todos="updateTodoOrder"
/>
</div>
</template>js arguments
<script>
import AddTodo from './components/AddTodo.vue';
import TodoList from './components/TodoList.vue';
import { Database, forwardOrder } from './database.js';
export default {
name: 'App',
components: {
AddTodo,
TodoList,
},
data() {
return {
todos: [],
order: forwardOrder,
}
},
created() {
this.db = new Database();
this.updateTodos();
},
methods: {
async addTodo(todo) {
await this.db.);
this.updateTodos(false);
},
async toggleTodo(togglePayload) {
await this.db.setTodoDone(togglePayload.id, togglePayload.done); this.updateTodos(false);
},
async deleteTodo(deletePayload) {
await this.db.deleteTodo(deletePayload.id);
this.updateTodos(false);
},
updateTodoOrder(sortTodosPayload) {
this.updateTodos(true);
},
async updateTodos(orderUpdated) {
let todos = await der);
if (orderUpdated) {
return
}
let idToIndex = {};
for (let i = 0; i < dos.length; i++) {
dos[i].id] = i;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论