经过了第十章节 浏览器 IndexedDB 简明教程 ( 十 ) - 读取数据 的 get()
方法,你可能会说,那么要怎么获取一个存储对象里的所有数据呢 ?
虽然 IDBObjectStore
提供了 getAll()
方法,但是好像该方法是在第二草案中出现,当前并没有得到良好的支持
难道没有其它办法了么?
答案是否定的,还有一个办法,叫做 「 遍历 」
游标 cursor
说起遍历数据,大家一定会想到什么 ? 比如下面的数据
1. 苹果 2. 香蕉 3. 梨 2. 香蕉 4. 桃
你怎么知道当前已经遍历到了哪条数据呢? 比如我们输出了 苹果
之后,要怎么知道下一个就是 香蕉
呢 ?
你肯定会说,我知道啊,因为刚刚我输出 苹果
的时候发现它的编号,我记得这个编号,那么下一个数据不就是把编号 +1 ,不就得到了 香蕉 的编号么 ?
对,你非常聪明
在我们编程中,我们把这种记住编号的方法叫做 「 游标 」 ( cursor )
IDBCursor
IndexedDB 中遍历数据也要记住,也要通过记住编号来获得,IndexedDB 中的 「 游标 」 是一个叫 IDBCursor
的对象
IDBCursor
也是一个异步操作集合
我们先来看看 IDBCursor
的对象提供了哪些方法和属性
IDBCursor 对象属性
属性 | 方法 |
---|---|
cursor.source | 只读,返回游标遍历的 IDBObjectStore 或 IDBIndex |
cursor.direction | 只读,游标遍历的方向 next: 从数据源开始位置遍历 nextunique: 从数据源开始位置开始遍历,当取值又重复时,只获取一次 prev: 从数据源的最后位置开始遍历 prevunique: 从数据源最后位置开始遍历,当取值又重复时,只获取一次 |
cursor.key | 只读,返回游标所在位置处记录的键。如果游标超出范围,则返回 undefined |
cursor.primaryKey | 只读,返回游标当前位置的主键。如果游标当前正在迭代或超出迭代范围,则设置为undefined 游标的主键可以是任何数据类型 |
cursor.key
其实就是上面我们所说的编号,我们重点介绍下 cursor.direction
让我们再次回到上面举的遍历的例子,我们知道,遍历有两种方式
-
一种是顺着遍历,从头到尾,也就是
1 -> 2 -> 3 -> 2 -> 4
,IndexedDB 把这种顺着遍历的方式称之为 `next -
另一种是倒着遍历,从尾到头,也就是
4 -> 2 -> 3 -> 2 -> 1
,IndexedDB 把这种遍历方式称之为prev
而至于 nextunique
和 prevunique
则是会排除重复值,比如两个 香蕉只取出现的第一个
IDBCursor 对象方法
方法 | 描述 |
---|---|
cursor.advice(count) | 游标移动的次数 |
cursor.continue(optional Key) | 继续沿着当前游标遍历方向,找到下一个能够匹配 key 参数的键。如果没有指定参数,则根据游标当前遍历方向,移动到下一个位置 |
cursor.delete( ) | 返回一个 IDBRequest 对象。在一个独立线程内删除游标所在位置处的记录(不移动游标),随后将游标设置为 null |
cursor.update(newValue) | 返回一个 IDBRequest 对象。在一个独立线程内,使用 newValue 来更新对象存储内游标当前位置处的值。如果游标指向的记录已被删除,则利用指定的 newValue 值创建一个新的记录 |
人如其名,方法名也是,我们重点介绍两个,剩下的我们会在后面的章节中提到
-
cursor.continue(optional_key)
该方法用于将游标移动到下一个位置,对于上面的范例来说,就是把编号 +1 或 -1 ( 取决于移动方向 cursor.direction ),如果指定了 key ,则会移动到下一个 key 的位置,那么移动距离可能就不是 +1 或 -1 了,而是 +3 +4 等
-
cursor.advice(count)
该方法会返回游标移动的次数,正常情况下,返回的值都是 1,因为不带参数的 cursor.continue 方法移动距离 如果给 cursor.continue 传递了一个 key,那么移动的距离可能就不是 1 了,而是这个操作移动的距离
游标实例
那么要怎么创建 IDBCursor 的实例呢? IDBCursor 没有提供相关的方法啊 !
是啊,IDBCursor 没有提供,但如果你回忆起了 存储对象 IDBObjectStore 就会想起它提供了 openCursor()
方法
IDBObjectStore.openCursor([range], [direction])
该返回 IDBRequest 对象,并在在一个独立的线程内,在对象存储的记录上创建一个游标
也就是说,我们的游标实例,是 IDBRequest.onsuccess
回调 event.target
对象
范例
下面的代码在 city
存储对象上创建一个游标,并遍历存储对象 city 中的所有数据
var db; //先删除 window.indexedDB.deleteDatabase('demo') var req = window.indexedDB.open('demo'); req.onerror = function (event) { console.log('打开数据库失败'); }; req.onsuccess = function (event) { console.log('打开数据库成功'); db = event.target.result; var ts = db.transaction( ['city'] ,'readwrite' ); var city_os = ts.objectStore('city') city_os.add({city_id:100000,'city_name':'北京'}); city_os.add({city_id:300000,'city_name':'天津'}); console.log('往 city 里添加了一条数据'); var ts2 = db.transaction( ['city'] ,'readwrite' ); var city_os2 = ts2.objectStore('city'); // 在 city 存储对象上创建一个游标 var req3 = city_os2.openCursor(); req3.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { console.log('city_id: ' + cursor.key); console.log('city_name: ' + cursor.value.city_name); cursor.continue(); } else { console.log('No more data'); } }; }; req.onupgradeneeded = function (event) { console.log('升级成功'); db = event.target.result; db.createObjectStore('city',{keyPath:'city_id'}); }
输出结果如下
升级成功 打开数据库成功 往 city 里添加了一条数据 city_id: 100000 city_name: 北京 city_id: 300000 city_name: 天津 No more data