菜单

前端的数据库:IndexedDB入门

2019年4月9日 - Ajax

前端的数据库:IndexedDB入门

2014/12/27 · 未分类 · IndexedDB

本文由 伯乐在线
cucr
翻译,黄利民
校稿。未经许可,禁止转载!
英文出处:www.codemag.com。欢迎加入翻译组

应用程序供给多少。对当先五分之三Web应用程序来说,数据在劳动器端组织和治本,客户端通过互连网请求获取。随着浏览器变得特别有能力,因而可选拔在浏览器存款和储蓄和操纵应用程序数据。

正文向您介绍名称为IndexedDB的浏览器端文书档案数据库。使用lndexedDB,你能够通过惯于在劳动器端数据库大致1致的方法创制、读取、更新和删除大批量的记录。请使用本文中可工作的代码版本去体验,完整的源代码能够通过GitHub库找到。

读到本学科的末尾时,你将驾驭IndexedDB的基本概念以及怎么着达成三个接纳IndexedDB执行总体的CRUD操作的模块化JavaScript应用程序。让我们有个别亲近IndexedDB并早先吧。

什么是IndexedDB

貌似的话,有二种差异品种的数据库:关系型和文书档案型(也号称NoSQL或对象)。关周全据库如SQL
Server,MySQL,Oracle的数据存款和储蓄在表中。文书档案数据库如MongoDB,CouchDB,Redis将数据集作为个人对象存款和储蓄。IndexedDB是叁个文书档案数据库,它在完全内放置浏览器中的1个沙盒环境中(强制依照(浏览器)同源策略)。图1出示了IndexedDB的数额,突显了数据库的结构

图片 1

图一:开发者工具查看3个object
store

全副的IndexedDB API请参见完整文书档案

介绍

IndexedDB正是一个数据库
其最大的性状是:
选取对象保存数据,而不是运用表来保存数据,同时,它是异步的

安顿规范

IndexedDB的架构很像在有的流行的劳动器端NOSQL数据库完结中的设计规范类型。面向对象数据通过object
stores(对象仓库)进行持久化,全体操作基于请求同时在事情限制内实施。事件生命周期使你能够支配数据库的布署,错误通过荒谬冒泡来使用API管理。

运用办法

指标仓库

object
store是IndexedDB数据库的根底。如若您使用过关周密据库,平时能够将object
store等价于二个多少库表。Object
stores包含3个或多个目录,在store中遵从壹对键/值操作,那提供一种高效稳定数据的诀要。

当你安顿三个object
store,你不可能不为store采纳三个键。键在store中能够以“in-line”或“out-of-line”的点子存在。in-line键通过在数额对象上引用path来有限扶助它在object
store的唯一性。为了注解那点,想想二个囊括电子邮件地址属性Person对象。您可以配备你的store使用in-line键emailAddress,它能担保store(持久化对象中的数据)的唯壹性。其它,out-of-line键通过单独于数据的值识别唯1性。在那种情景下,你能够把out-of-line键比作贰个平头值,它(整数值)在关周详据库中充当记录的主键。

图一出示了职分数据保存在职务的object
store,它使用in-line键。在这几个案例中,键对应于对象的ID值。

接二连三数据库

要选拔它必须先打开,通过 indexDB.open(name, version)主意打开1个数据库

据说事务

区别于一些价值观的关周全据库的落到实处,每个对数据库操作是在2个业务的内外文中执行的。事务限制1次影响1个或八个object
stores,你通过传播七个object store名字的数组到创建工作限制的函数来定义。

开创工作的第3个参数是事情形式。当呼吁一个事务时,必须决定是根据只读还是读写情势请求访问。事务是财富密集型的,所以只要您不须求更改data
store中的数据,你只要求以只读格局对object stores集合进行呼吁访问。

清单二示范了何等运用合适的方式创立2个作业,并在那片小说的 Implementing
Database-Specific Code
 部分进行了详尽座谈。

indexDB.open()方法的规律

分为三种状态:
一. 传唱的数据库不设有
当传入的数据库不存在时,该办法就会创设三个名叫name的数据库,并开拓它,此时,会先触发upgradeneeded事件;调用该函数会再次来到三个IDBRequest对象,能够在该对象上添加onsuccess事件onerror事件
注意:当打开二个不设有的数据库时会触发upgradeneeded事件,那是触发该事件的1种途径,为何会触发该事件吧?该事件有啥效劳?留个难题在此时,等会解答。

二. 传唱的数据仓库储存在
那边分为三种情形:

遵照请求

以至于那里,有二个反复出现的核心,您恐怕早就注意到。对数据库的每回操作,描述为经过3个呼吁打开数据库,访问四个object
store,再持续。IndexedDB
API天生是基于请求的,那也是API异步个性提醒。对于你在数据库执行的历次操作,你必须首先为那个操作创制三个伸手。当呼吁完结,你可以响应由请求结果爆发的事件和错误。

本文达成的代码,演示了什么运用请求打开数据库,创制二个工作,读取object
store的内容,写入object store,清空object store。

upgradeneeded事件

触发该事件的准绳:当打开的数据库不存在,恐怕传播的数据库版本version高于当前版本,则会触发该事件

upgradeneeded事件的功能:当打开了3个数据库之后,须要开拓2个名为:目的存款和储蓄空间
的钱物(能够掌握为数据正是存放在这一个空间里面,3个数据库能够创制八个对象存款和储蓄空间),而
对象存款和储蓄空间 只能在upgradeneeded事件的处理函数中创建

选取时,注意以下三种情状:

  1. 当大家第二遍打开成立数据库时,会接触upgradeneeded事件,大家就要求在里面成立对象存款和储蓄空间

  2. 当大家对数据库版本举办立异时,也会触发该事件,那时能够在此创造新的目的存款和储蓄空间,原来的指标存款和储蓄空间依然存在

注意:假若急需对指标存款和储蓄空间拓展改动,那么只好先将积存在它在那之中的数码读取出来,再将其除去,然后接纳新的选项去创设它,再写入原来的多少

开辟数据库并创设对象存款和储蓄空间的代码:

// 对于该API,各浏览器还未同一,所以需要对一些接口添加前缀
window.indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBTransaction;

// 判断浏览器是否支持IndexedDB
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB.")
}

var request , db;
// 打开或创建 名为dbName的数据库
request = window.indexedDB.open('dbName', 2)
request.onsuccess = function (event) {
   db = event.target.result;
}

request.onerror = function (event) {
   console.log('错误代码: ' + event.target.errorCode);
}

request.onupgradeneeded = function(event) {
  db = event.target.result;  // 
  // 创建一个   对象存储空间,名为customers
  var objectStore = db.createObjectStore('customers', {keyPath: 'ssn'});
  // 对于某些数据,可以为一个对象存储空间指定多个键。比如,若要通过用户ID 和用户名 两种方式来保存用户资料,就需要通过两个键来存取记录
  // 因此可以使用createIndex,名字是有可能重复的,所以其unique 设置为 false ;第一个name是索引的名字,该名字是索引的名字,第二个name是索引的属性的名字,该名字要与对象中的属性相同
  objectStore.createIndex('name', 'name', { unique: false});

  // 创建一个email的索引,该email是独特的,所以 unique 设置为 true
  objectStore.createIndex('email', 'email', { unique: true});
}

打开数据库的请求生命周期

IndexedDB使用事件生命周期管理数据库的打开和陈设操作。图二演示了多少个开辟的伸手在早晚的环境下发生upgrade
need事件。

图片 2

图2:IndexedDB打开请求的生命周期

持有与数据库的交互伊始于二个开拓的伸手。试图打开数据库时,您必须传递2个被呼吁数据库的本子号的整数值。在开辟请求时,浏览器相比你传入的用于打开请求的版本号与事实上数据库的版本号。如若所请求的版本号高于浏览器中当前的版本号(或然未来从未有过存在的数据库),upgrade
needed事件触发。在uprade
need事件之间,你有机会通过抬高或移除stores,键和索引来操纵object stores。

万1所请求的数据库版本号和浏览器的脚下版本号相同,也许升级历程做到,3个打开的数据库将赶回给调用者。

储存数据

仓储数据有二种艺术:add()方法put()方法

那三种方法的区分首要反映在:当要添加数据的靶子存款和储蓄空间中早就存在有相同键的数额时,使用add()方法添加数据会报错误,而put()方法则会对现有数量进行立异,所以add()方法一般用来开头化数据,而put()方法用于更新数据

代码如下:

// customerData 为要存储的数据
const customerData = [{ ssn: '444-44-4444', name: 'AAA', age: 35, email: '[AAA@company.com](mailto:AAA@company.com)'},{ ssn: '666-66-6666', name: 'CCC', age: 35, email: '[CCC@company.com](mailto:CCC@company.com)'},{ ssn: '777-77-7777', name: 'DDD', age: 32, email: '[DDD@home.org](mailto:DDD@home.org)'},{ ssn: '555-55-5555', name: 'BBB', age: 32, email: '[BBB@home.org](mailto:BBB@home.org)'},
];

// 创建一个事务,该事务将要对名为“customers”的对象存储空间进行 read和write 操作,并返回事务索引
let transaction = db.transaction('customers', 'readwrite'); 

// 取得索引后,使用objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间,这两步是必须的
let store = transaction.objectStore('customers'); 

// 添加数据到数据库中
for (var i in customerData) {
  // 返回的req也是一个对象,可以为其添加onsuccess和onerror事件,来检测数据是否添加成功
  let req = store.put(customerData[i]);   // 往一个存储空间中添加数据

}
// 判断事务整个操作完成
transaction.oncomplete = function(event) {
  console.log(event.target);
  alert('存储数据完成');
};
}

如上就将数据存款和储蓄到数据库dbNames的customers对象存款和储蓄空间中

地方代码中涉嫌了
[事务],那里先记住:凡是涉及到对数据库的读写删除操作,都急需通过
[事务] 来完成

错误冒泡

本来,有时候,请求恐怕不会按预期实现。IndexedDB
API通过荒谬冒泡效果来支援跟踪和保管漏洞百出。要是二个一定的请求境遇错误,你能够尝试在呼吁对象上处理错误,只怕您能够允许错误通过调用栈冒泡向上传递。这些冒泡本性,使得你不供给为每一个请求完成特定错误处理操作,而是能够选拔只在三个更加高级别上添加错误处理,它给您二个机会,保持您的错误处理代码简洁。本文中贯彻的例子,是在贰个高级别处理错误,以便更加细粒度操作发生的任何不当冒泡到通用的错误处理逻辑。

事情和查询操作数据

最简易的成立工作的主意是:
var transaction = db.transaction(); // db就是前面的数据库对象
那种措施开创的政工,只好读取数据库中保留的具有指标

貌似用法是:
var transaction = db.transaction('customes', 'readwrite');
代表只加载customers对象存款和储蓄空间中的数据,并且是以可读可写的主意加载

①经不传首个参数,则代表只可访问,不可修改;

那边重回的transaction是业务的目录

下一场使用objectStore()主意并传播对象存款和储蓄空间的称号,就足以访问特定的囤积空间了;

如下:

let transaction = db.transaction('customers', 'readwrite'); 
let store = transaction.objectStore('customers'); 

取得了下面的store后,大家能够行使如下方法对数据开始展览操作:

注意:通过oncomplete事件目的,访问不到get()请求再次来到的别的数据,必须在响应请求的onsuccess事件处理程序中才能访问到数量

浏览器支持

恐怕在开发Web应用程序最要紧的难题是:“浏览器是或不是支持自身想要做的?“即便浏览器对IndexedDB的支撑在一而再增强,选用率并不是大家所期待的那样普遍。图叁来得了caniuse.com网址的告诉,协理IndexedDB的为66%多一小点。最新版本的银狐,Chrome,Opera,Safar,iOS
Safari,和Android完全帮忙IndexedDB,Internet
Explorer和OPPO部分支持。就算那些列表的跟随者是冲动的,但它从不告知全体传说。

图片 3

图3:浏览器对IndexedDB的支撑,来自caniuse.com

除非可怜新本子的Safari和iOS Safari
支持IndexedDB。据caniuse.com显示,那只占大致0.01%的天下浏览器采纳。IndexedDB不是3个您觉得能够理所当然获得扶助的现代Web
API,不过你将便捷会这么认为。

使用游标查询数据

应用工作能够直接通过
已知的键检索单个对象。而在急需摸索多少个指标时,则需求在工作内创立游标。

游标并不会提前收集结果,游标先指向结果中的第三项,在吸收查找下一项的指令时,才会针对下1项

如下:

let transaction = db.transaction('customers', 'readwrite'),
let store = transaction.objectStore('customers'),
let request = store.openCursor(null) ; // 这里创建游标
request.onsuccess = function (event) {
  // event.target.result 中保存的是在存储空间中查询到的对象
  // event.target.result 中有几个属性值,可以了解到查询到的对象中的细节,
  // key: 当前访问的对象的键
  // value:当前访问的实际对象
  // primaryKey: 游标使用的键
  // direction:数值,表示游标移动的方向
  let cursor = event.target.result;
  let value, updateRequest, deleteRequest;

  // 这里必须要检查游标中是否有数据
  if (cursor) {
    if (cursor.key === '555-55-5555') {
      value = cursor.value;   // 获取到实际的访问对象
      value.name = 'hexon';   // 修改对象的name属性
      // 调用update()方法可以用指定的对象,更新对象的value
      updateRequest = cursor.update(value);     
      updateRequest.onsuccess = function() {
          // 处理成功
       }
    }
    cursor.continue() ;  // 移动到下一项,会触发下一次请求,同时成功则触发request.onsuccess
  }
}

下边例子中,能够应用cursor.delete()艺术删除当前项

另壹种选拔

浏览器协理地点数据库并不是从IndexedDB才起来落到实处,它是在WebSQL贯彻之后的壹种新章程。类似IndexedDB,WebSQL是一个客户端数据库,但它作为一个关周到据库的完结,使用结构化查询语言(SQL)与数据库通讯。WebSQL的野史充满了波折,但底线是绝非主流的浏览器厂商对WebSQL继续扶助。

壹旦WebSQL实际上是2个舍弃的技艺,为何还要提它呢?有趣的是,WebSQL在浏览器里获得巩固的支撑。Chrome,
Safari, iOS Safari, and
Android 浏览器都帮助。其余,并不是这个浏览器的新星版本才提供支撑,许多这一个最新最棒的浏览器此前的版本也能够支持。有趣的是,借使您为WebSQL添加辅助来支撑IndexedDB,你突然发现,许多浏览器厂商和版本成为支撑浏览器内置数据库的某种化身。

因而,如若你的应用程序真正须要三个客户端数据库,你想要达到的最高级别的采纳恐怕,当IndexedDB不可用时,可能你的应用程序只怕看起来供给选拔选拔WebSQL来支撑客户端数据架构。尽管文书档案数据库和关全面据库管理数据有综上说述的差距,但借使您有正确的说梅止渴,就能够运用本地数据库营造三个应用程序。

键范围

游标也能够承受叁个键,也正是经过键来设定游标查找的限定;
代码如下:

<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>WebStorage DEMO</title>
</head>
<body>
<div class=”networkStatus”>
<button class=”clear”>清空数据</button>
<button class=”add”>添加数量</button>
<button class=”query”>查询数据</button>
<button class=”delete”>删除数据</button>
<button class=”cursor”>使用游标查询</button>
<button class=”keyRange”>使用keyrange查询</button>
<button class=”index”>使用index</button>
</div>

<script>
let network = document.querySelector(‘.networkStatus’),
addBtn = document.querySelector(‘.add’),
queryBtn = document.querySelector(‘.query’),
deleteBtn = document.querySelector(‘.delete’),
cursorBtn = document.querySelector(‘.cursor’),
clearBtn = document.querySelector(‘.clear’),
keyRange = document.querySelector(‘.keyRange’),
indexBtn = document.querySelector(‘.index’)
;

// 判断网路是不是在线
// if (navigator.onLine) {
// network.innerText = “互连网在线”;
// } else {
// network.innerText = “网络掉线”;
// }

// // 监察和控制网络状态的事件:online 和 offline, 那四个事件在window对象上
// window.addEventListener(‘online’, () => {
// network.innerText = “互联网在线”;
// });

// window.addEventListener(‘offline’, () => {
// network.innerText = “互连网掉线”;
// });

//——–cookie的使用—————
let CookieUtil = {
get: (name) => {
let cookieName = encodeURIComponent(name) + “=”,
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;

  if (cookieStart > -1) {
    let cookieEnd = document.cookie.indexOf(';', cookieStart);
    if (cookieEnd === -1) {
      cookieEnd = document.cookie.length;
    }
    cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
  }

  return cookieValue;
},
set: function (name, value, expires, path, domain, secure) {
  let cookieText = encodeURIComponent(name) + '=' +
                   encodeURIComponent(value);

  if (expires instanceof Date) {
    cookieText += '; expires=' + expires.toGMTString();
  }

  if (path) {
    cookieText += '; path=' + path;
  }

  if (domain) {
    cookieText += '; domain=' + domain;
  }

  if (secure) {
    cookieText += '; secure';
  }

  document.cookie = cookieText;
},

// 删除cookie, 并没有直接的删除cookie的方法,这里通过重新设置cookie名称,来对cookie进行替换
// 同时 将过期时间expires设置为过去的时间,
unset: function(name, path, domain, secure) {
  this.set(name, '', new Date(0), path, domain, secure);
}

}

CookieUtil.set(‘name’, ‘hexon’);
CookieUtil.set(‘book’, ‘Profession Javascript’);

// 读取cookie的值
// console.log(CookieUtil.get(‘name’));
// console.log(CookieUtil.get(‘book’));

// 删除cookie
CookieUtil.unset(‘name’);
CookieUtil.unset(‘book’);

// 设置cookie, 蕴含它的路径、域、失效日期
CookieUtil.set(‘name’, ‘Hexon’, ‘books/projs/’,
www.wrox.com’, new
Date(‘January 1, 2017’));

// 删除刚刚安装的cookie
CookieUtil.unset(‘name’, ‘books/projs/’,
www.www.wrox.com’);

// 设置安全的cookie
CookieUtil.unset(‘name’, ‘hexon’, null, null, null, null, true)

// — IndexedDB 数据库的接纳
var request = window.indexedDB.open(‘dbName’, 2)
var db;
const dbName = ‘the_name’;
// 创立三个数量
const customerData = [
{ ssn: ‘444-44-4444’, name: ‘AAA’, age: 35, email:
AAA@company.com‘},
{ ssn: ‘666-66-6666’, name: ‘CCC’, age: 35, email:
CCC@company.com‘},
{ ssn: ‘777-77-7777’, name: ‘DDD’, age: 32, email:
DDD@home.org‘},
{ ssn: ‘555-55-5555’, name: ‘BBB’, age: 32, email:
BBB@home.org‘},

];

window.indexedDB = window.indexedDB || window.msIndexedDB ||
window.mozIndexedDB || window.webkitIndexedDB;
window.IDBTransaction = window.IDBTransaction ||
window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE:
“readwrite”};
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange ||
window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBTransaction;

if (!window.indexedDB) {
window.alert(“Your browser doesn’t support a stable version of
IndexedDB.”)
}

// 三是确立的数据库版本,假若名称为MyTestDatabase的数据库不存在,就会创设该数据库,然后
onupgradeneeded 事件会被触发;
// 借使数据仓库储存在,可是对版本升级了,也会触发onupgradeneeded事件,
// 注意:版本号是3个 unsigned long long
类型的值,由此不用使用float,不然会将其转移为其最接近的整数

// 生成处理程序
request.onerror = function (event) {
// do Something
alert(‘Database error: ‘ + event.target.errorCode);
};

request.onsuccess = function (event) {
// do Something
console.log(‘成立数据库成功’);
db = event.target.result; // 创设成功后,e.target.result
中储存的是IDBDatabase对象的实例
}

// 当创制叁个新的多少库 可能 更新已存在数据库的本子,
onupgradeneeded事件将会被触发,新的指标存款和储蓄在event.target.result中。
//
在该处理程序中,数据库已经持有先前版本的对象存款和储蓄,因而无需再次创设那些指标存款和储蓄,只必要创设任何大家须要的靶子存款和储蓄,或然
//
从从前版本中剔除不在须要的目的存款和储蓄。假使急需变更当前目的存款和储蓄,则必须先删除旧的靶子存款和储蓄,然后在选用新的选项创设。
// 删除旧的对象存款和储蓄,在其上的音讯都会被删去;
//
注意:该事件是唯1叁个力所能及对数据库举行操作的地方,在该事件之中,你对目的存款和储蓄进行删除、修改或移除索引
request.onupgradeneeded = function(event) {
console.log(‘onupgradeneeded’);
var db = event.target.result;

// 创建一个   对象存储空间,名为customers
var objectStore = db.createObjectStore('customers', {keyPath: 'ssn'});
// 对于某些数据,可以为一个对象存储空间指定多个键。比如,若要通过用户ID 和用户名 两种方式来保存用户资料,就需要通过两个键来存取记录
// 因此可以使用createIndex,名字是有可能重复的,所以其unique 设置为 false ;第一个name是索引的名字,该名字是索引的名字,第二个name是索引的属性的名字,该名字要与对象中的属性相同
objectStore.createIndex('name', 'name', { unique: false});

// // 创建一个email的索引,该email是独特的,所以 unique 设置为 true
objectStore.createIndex('email', 'email', { unique: true});

}

function save(data) {
///
对于数据库的指标存款和储蓄空间中多少的读取或改动数据,都要经过事物来公司具有操作
// 最简易的创造事物的不二法门是:var transaction = db.transaction();
let transaction = db.transaction(‘customers’, ‘readwrite’); //
创造三个作业,并定义该业务的操作为 “readwrite” ,并回到其索引
let store = transaction.objectStore(‘customers’); //
取得索引后,使用objectStore()方法并传播存款和储蓄空间的名目,就足以访问特定的存款和储蓄空间

for (var i in customerData) {
  let req = store.put(customerData[i]);   // 往一个存储空间中添加数据
}

transaction.oncomplete = function(event) {
  console.log(event.target);
  alert('存储数据完成');
};

transaction.onsuccess = function(event ) {
  console.log('onsuccess 事件');
}

}

function clear() {
// body…
let transaction = db.transaction(‘customers’, ‘readwrite’);
let store = transaction.objectStore(‘customers’).clear();
store.onerror = function(event) {
console.log(‘清空数据失败’);
}
store.onsuccess = function(event) {
console.log(‘清空数据成功’);
}
}

// 使用事务 直接通过已知的键索引 单个对象 (只可以索引单个对象)
function getData() {
let transaction = db.transaction(‘customers’, ‘readwrite’); //
创立1个事物, 并定义该事情的操作为 “readonly”
let store = transaction.objectStore(‘customers’).get(’44肆-44-444肆’); //
使用get() 能够博得值

store.onerror = function (event) {
  alert('did not get the object');
}

store.onsuccess = function (event) {
  var result = event.target.result;
  console.log(result);
  alert('获取数据完成! 年龄是: ' + result.age);
}

}

function deleteData() {
let transaction = db.transaction(‘customers’, ‘readwrite’);
let store = transaction.objectStore(‘customers’);
store.delete(‘444-44-4444’);
alert(‘s删除数据形成’);
}

// 在工作内创造游标查询 能够索引 多少个指标(注意: 是四个目的)
// 游标不提前手提式有线电话机结果
function cursorQuery() {
let transaction = db.transaction(‘customers’, ‘readwrite’),
store = transaction.objectStore(‘customers’),
request = store.openCursor(null) ; // 那里开创游标

request.onsuccess = function (event) {

  // event.target.result 中保存的是在存储空间中查询到的对象
  // event.target.result 中有几个属性值,可以了解到查询到的对象中的细节,
  // key: 当前访问的对象的键
  // value:当前访问的实际对象
  // primaryKey: 游标使用的键
  // direction:数值,表示游标移动的方向

  let cursor = event.target.result;
  let value, updateRequest, deleteRequest;
  if (cursor) {
  //   if (cursor.key === '555-55-5555') {
  //     value = cursor.value;   // 获取到实际的访问对象
  //     value.name = 'hexon';   // 修改对象的name属性

  //     updateRequest = cursor.update(value);      // 调用update()方法可以用指定的对象,更新对象的value
  //     updateRequest.onsuccess = function() {
  //       // 处理成功
  //     }
  //     updateRequest.onerror = function() {
  //       // 处理失败
  //     }


  //     // 使用游标删除当前项
  //     // deleteRequest = cursor.delete();
  //     // deleteRequest.onsuccess = function() {
  //     //   // 删除成功处理
  //     // }
  //     // deleteRequest.onerror = function() {
  //     //   // 删除失败处理
  //     // }


  //   }
  //   console.log(event.target.result);
  // }
  console.log(cursor.value);
  cursor.continue();      // 移动到下一项,
  }
  request.onerror = function(event) {
    console.log('游标查询创建失败')
  }
}

}

// 使用keyrange查询
function keyRangeQuery() {
let transaction = db.transaction(‘customers’, ‘readwrite’)
let store = transaction.objectStore(‘customers’);
// 使用bound()方法 定义键范围
let range = IDBKeyRange.bound(‘555-55-5555’, ‘777-77-7777’, true,
false);
// 将键传入游标创造
let request = store.openCursor(range);

request.onsuccess = function(event) {
  let cursor = event.target.result;
  if (cursor) {
    console.log('游标查询到的值' + JSON.stringify(cursor.value));
    cursor.continue()     // 移动到下一项
  }

}

request.onerror = function(event) {
  console.log("使用游标 + keyrange 查询失败")
}

}

// 使用索引
function useIndex() {
let store = db.transaction(‘customers’).objectStore(‘customers’),
index = store.index(‘name’);
request = index.openCursor();
request.onsuccess = function (event) {
let cursor = event.target.result;
if (cursor) {
console.log(cursor);
cursor.continue();
}
}
}

addBtn.addEventListener(‘click’, function(e) {
save();
}, false);

deleteBtn.addEventListener(‘click’, function(e) {
deleteData();
}, false);

queryBtn.addEventListener(‘click’, function(e) {
getData();
}, false);

cursorBtn.addEventListener(‘click’, function(e) {
cursorQuery();
}, false);

clearBtn.addEventListener(‘click’, function(e) {
clear();
}, false);

keyRange.addEventListener(‘click’, function(e) {
keyRangeQuery();
}),

indexBtn.addEventListener(‘click’, function(e) {
useIndex();
})

</script>

</body>
</html>

IndexedDB是还是不是合乎作者的应用程序?

当今最重大的难点:“IndexedDB是或不是合乎自身的应用程序?“像过去一致,答案是一定的:“视情形而定。“首先当你打算在客户端保存数据时,你会思索HTML伍本土存款和储蓄。本地存款和储蓄获得大规模浏览器的帮助,有相当简单使用的API。简单有其优势,但其劣势是无力回天支撑复杂的寻找策略,存储大批量的多少,并提供业务补助。

IndexedDB是2个数据库。所以,当您想为客户端做出决定,考虑你怎么样在服务端选用1个持久化介质的数据库。你或者会问自身有个别题材来帮衬控制客户端数据库是不是顺应你的应用程序,包涵:

若果你对中间的别样难点回复了“是的”,很有希望,IndexedDB是您的应用程序的四个很好的候选。

使用IndexedDB

方今,你早就有时机熟稔了有的的壹体化概念,下一步是开头完成基于IndexedDB的应用程序。第叁个步骤需求统壹IndexedDB在区别浏览器的落到实处。您能够很不难地抬高种种厂商性格的挑三拣四的检讨,同时在window对象上把它们设置为法定对象相同的名目。上面包车型大巴清单展现了window.indexedDB,window.IDBTransaction,window.IDBKeyRange的终极结出是如何都被更新,它们被安装为相应的浏览器的特定完结。

JavaScript

window.indexedDB = window.indexedDB || window.mozIndexedDB ||
window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction =
window.IDBTransaction || window.webkitIDBTransaction ||
window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange ||
window.webkitIDBKeyRange || window.msIDBKeyRange;

1
2
3
4
5
6
7
8
9
10
window.indexedDB = window.indexedDB ||
                   window.mozIndexedDB ||
                   window.webkitIndexedDB ||
                   window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction ||
                   window.webkitIDBTransaction ||
                   window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange ||
                   window.webkitIDBKeyRange ||
                   window.msIDBKeyRange;

明天,各个数据库相关的大局对象具备正确的版本,应用程序能够准备利用IndexedDB初阶工作。

使用概述

在本教程中,您将学习怎么着创造3个行使IndexedDB存储数据的模块化JavaScript应用程序。为了理解应用程序是哪些行事的,参考图四,它讲述了任务应用程序处于空白状态。从那边您能够为列表添加新义务。图5体现了录入了多少个职分到系统的画面。图陆出示怎么删除3个职分,图七展现了正在编纂义务时的应用程序。

图片 4

图四:空白的天职应用程序

图片 5

图伍:职责列表

图片 6

图陆:删除职责

图片 7

图柒:编辑职务
前天你熟谙的应用程序的功效,下一步是初始为网址铺设基础。

铺设基础

以此例子从贯彻如此多少个模块开始,它肩负从数据库读取数据,插入新的靶子,更新现有对象,删除单个对象和提供在一个object
store删除全数目的的选项。那个事例完成的代码是通用的数目访问代码,您能够在任何object
store上利用。

本条模块是通过三个随即施行函数表明式(IIFE)实现,它采用对象字面量来提供社团。上边包车型客车代码是模块的摘要,表明了它的着力构造。

JavaScript

(function (window) { ‘use strict’; var db = { /* implementation here
*/ }; window.app = window.app || {}; window.app.db = db; }(window));

1
2
3
4
5
6
7
8
(function (window) {
    ‘use strict’;
    var db = {
        /* implementation here */
    };
    window.app = window.app || {};
    window.app.db = db;
}(window));

用这么的协会,能够使那么些应用程序的兼具逻辑封装在三个名字为app的单对象上。其余,数据库相关的代码在三个号称db的app子对象上。

本条模块的代码应用IIFE,通过传递window对象来保管模块的熨帖限制。使用use
strict确认保障那一个函数的代码函数是依据(javascript严厉形式)严刻编写翻译规则。db对象作为与数据库交互的兼具函数的重要容器。最终,window对象检查app的实例是不是存在,假如存在,模块使用当前实例,即便不设有,则开创一个新对象。一旦app对象成功再次回到或成立,db对象附加到app对象。

本文的别的部分将代码添加到db对象内(在implementation
here会
讲评),为应用程序提供一定于数据库的逻辑。由此,如你所见本文前边的某当中定义的函数,想想父db对象活动,但全数其余成效都是db对象的积极分子。完整的数据库模块列表见清单贰。

Implementing Database-Specific Code

对数据库的各样操作关联着二个先决条件,即有二个开辟的数据库。当数据库正在被打开时,通过检查数据库版本来判定数据库是或不是供给任何改动。上面包车型地铁代码展现了模块如何跟踪当前版本,object
store名、某成员(保存了一旦数据库打开请求完毕后的数据库当前实例)。

JavaScript

version: 1, objectStoreName: ‘tasks’, instance: {},

1
2
3
version: 1,
objectStoreName: ‘tasks’,
instance: {},

在那里,数据库打开请求产生时,模块请求版本一数据库。借使数据库不设有,也许版本小于一,upgrade
needed事件在开拓请求完结前触发。那么些模块被设置为只行使一个object
store,所以名字直接定义在此处。最终,实例成员被创建,它用来保存一旦打开请求完毕后的数据库当前实例。

接下去的操作是完毕upgrade
needed事件的事件处理程序。在那边,检查当前object
store的名字来判断请求的object store名是或不是存在,若是不设有,创制object
store。

JavaScript

upgrade: function (e) { var _db = e.target.result, names =
_db.objectStoreNames, name = db.objectStoreName; if
(!names.contains(name)) { _db.createObjectStore( name, { keyPath: ‘id’,
autoIncrement: true }); } },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upgrade: function (e) {
    var
        _db = e.target.result,
        names = _db.objectStoreNames,
        name = db.objectStoreName;
    if (!names.contains(name)) {
        _db.createObjectStore(
            name,
            {
                keyPath: ‘id’,
                autoIncrement: true
            });
    }
},

在那些事件处理程序里,通过事件参数e.target.result来访问数据库。当前的object
store名称的列表在_db.objectStoreName的字符串数组上。以后,假若object
store不设有,它是经过传递object
store名称和store的键的定义(自增,关联到数量的ID成员)来创制。

模块的下两个效应是用来捕获错误,错误在模块分歧的乞请创设时冒泡。

JavaScript

errorHandler: function (error) { window.alert(‘error: ‘ +
error.target.code); debugger; },

1
2
3
4
errorHandler: function (error) {
    window.alert(‘error: ‘ + error.target.code);
    debugger;
},

在此地,errorHandler在3个警告框显示此外不当。那个函数是明知故犯保持简单,对开发协调,当你学习使用IndexedDB,您可以很不难地来看别的错误(当他俩产生时)。当你准备在生育条件使用那么些模块,您要求在这些函数中贯彻部分错误处理代码来和您的应用程序的上下文打交道。

以后基础完毕了,这1节的别的部分将演示怎样促成对数据库执行一定操作。第壹个要求检查的函数是open函数。

JavaScript

open: function (callback) { var request = window.indexedDB.open(
db.objectStoreName, db.version); request.onerror = db.errorHandler;
request.onupgradeneeded = db.upgrade; request.onsuccess = function (e) {
db.instance = request.result; db.instance.onerror = db.errorHandler;
callback(); }; },

1
2
3
4
5
6
7
8
9
10
11
12
open: function (callback) {
    var request = window.indexedDB.open(
        db.objectStoreName, db.version);
    request.onerror = db.errorHandler;
    request.onupgradeneeded = db.upgrade;
    request.onsuccess = function (e) {
        db.instance = request.result;
        db.instance.onerror =
            db.errorHandler;
        callback();
    };
},

open函数试图打开数据库,然后实施回调函数,告知数据库成功打开药方可准备接纳。通过访问window.indexedDB调用open函数来创造打开请求。那些函数接受你想打开的object
store的名目和您想行使的数据库版本号。

假定请求的实例可用,第壹步要拓展的行事是安装错误处理程序和升迁函数。记住,当数据库被打开时,借使脚本请求比浏览器里更加高版本的数据库(恐怕一旦数据库不设有),升级函数运行。不过,即便请求的数据库版本匹配当前数据库版本同时未有不当,success事件触发。

假设全勤成功,打开数据库的实例能够从呼吁实例的result属性获得,这么些实例也缓存到模块的实例属性。然后,onerror事件设置到模块的errorHandler,作为未来任何请求的失实捕捉处理程序。最终,回调被实施来报告调用者,数据库已经开辟并且正确地安排,能够接纳了。

下叁个要落到实处的函数是helper函数,它回到所请求的object store。

JavaScript

getObjectStore: function (mode) { var txn, store; mode = mode ||
‘readonly’; txn = db.instance.transaction( [db.objectStoreName],
mode); store = txn.objectStore( db.objectStoreName); return store; },

1
2
3
4
5
6
7
8
9
getObjectStore: function (mode) {
    var txn, store;
    mode = mode || ‘readonly’;
    txn = db.instance.transaction(
        [db.objectStoreName], mode);
    store = txn.objectStore(
        db.objectStoreName);
    return store;
},

在此地,getObjectStore接受mode参数,允许你决定store是以只读依然读写方式请求。对于那一个函数,暗中认可mode是只读的。

各种针对object
store的操作都是在叁个东西的内外文中执行的。事务请求接受四个object
store名字的数组。这一个函数此番被计划为只使用一个object
store,然则一旦你需求在业务中操作多少个object store,你需求传递多个object
store的名字到数组中。事务函数的第三个参数是3个情势。

要是事情请求可用,您就能够透过传递须要的object
store名字来调用objectStore函数以赢得object
store实例的访问权。这几个模块的其余函数使用getObjectStore来博取object
store的访问权。

下2个落到实处的函数是save函数,执行插入或更新操作,它依照传入的数额是不是有二个ID值。

JavaScript

save: function (data, callback) { db.open(function () { var store,
request, mode = ‘readwrite’; store = db.getObjectStore(mode), request =
data.id ? store.put(data) : store.add(data); request.onsuccess =
callback; }); },

1
2
3
4
5
6
7
8
9
10
11
12
save: function (data, callback) {
    db.open(function () {
        var store, request,
            mode = ‘readwrite’;
 
        store = db.getObjectStore(mode),
        request = data.id ?
            store.put(data) :
            store.add(data);
        request.onsuccess = callback;
    });
},

save函数的四个参数分别是须要保留的数额对象实例和操作成功后需求履行的回调。读写形式用于将数据写入数据库,它被传到到getObjectStore来收获object
store的二个可写实例。然后,检查数据对象的ID成员是否存在。假诺存在ID值,数据必须创新,put函数被调用,它创制持久化请求。不然,假设ID不设有,那是新数据,add请求重回。最后,不管put或然add
请求是或不是执行了,success事件处理程序需求设置在回调函数上,来告诉调用脚本,1切进展顺遂。

下1节的代码在清单1所示。getAll函数首先打开数据库和做客object
store,它为store和cursor(游标)分别设置值。为数据库游标设置游标变量允许迭代object
store中的数据。data变量设置为三个空数组,充当数据的器皿,它回到给调用代码。

在store访问数据时,游标遍历数据库中的每条记下,会触发onsuccess事件处理程序。当每条记下走访时,store的多寡能够透过e.target.result事件参数获得。固然事实上数目从target.result的value属性中取得,首先须要在盘算访问value属性前确认保证result是贰个实用的值。假如result存在,您能够添加result的值到数据数组,然后在result对象上调用continue函数来继续迭代object
store。最终,要是未有reuslt了,对store数据的迭代截至,同时数据传递到回调,回调被执行。

近年来模块能够从data
store获得全体数据,下贰个亟需达成的函数是负责访问单个记录。

JavaScript

get: function (id, callback) { id = parseInt(id); db.open(function () {
var store = db.getObjectStore(), request = store.get(id);
request.onsuccess = function (e){ callback(e.target.result); }; }); },

1
2
3
4
5
6
7
8
9
10
11
get: function (id, callback) {
    id = parseInt(id);
    db.open(function () {
        var
            store = db.getObjectStore(),
            request = store.get(id);
        request.onsuccess = function (e){
            callback(e.target.result);
        };
    });
},

get函数执行的率先步操作是将id参数的值转换为2个平头。取决于函数被调用时,字符串或整数都恐怕传递给函数。这几个达成跳过了对借使所给的字符串无法转换来整数该咋办的情景的拍卖。1旦贰个id值准备好了,数据库打开了和object
store能够访问了。获取访问get请求出现了。请求成功时,通过传播e.target.result来执行回调。它(e.target.result)是经过调用get函数到手的单条记录。

近日封存和选取操作已经冒出了,该模块还亟需从object store移除数量。

JavaScript

‘delete’: function (id, callback) { id = parseInt(id); db.open(function
() { var mode = ‘readwrite’, store, request; store =
db.getObjectStore(mode); request = store.delete(id); request.onsuccess =
callback; }); },

1
2
3
4
5
6
7
8
9
10
11
‘delete’: function (id, callback) {
    id = parseInt(id);
    db.open(function () {
        var
            mode = ‘readwrite’,
            store, request;
        store = db.getObjectStore(mode);
        request = store.delete(id);
        request.onsuccess = callback;
    });
},

delete函数的称号用单引号,因为delete是JavaScript的保留字。这可以由你来决定。您能够采取命名函数为del或任何名目,不过delete用在那个模块为了API尽只怕好的表明。

传送给delete函数的参数是目的的id和一个回调函数。为了保持这一个实现简单,delete函数约定id的值为整数。您能够选拔制造二个更健全的贯彻来处理id值不可能分析成整数的荒谬例子的回调,但为了引导原因,代码示例是明知故犯的。

只要id值能保障转换来贰个平头,数据库被打开,三个可写的object
store得到,delete函数传入id值被调用。当呼吁成功时,将履行回调函数。

在好几情状下,您大概必要删除三个object
store的享有的记录。在那种情况下,您访问store同时免去全部剧情。

JavaScript

deleteAll: function (callback) { db.open(function () { var mode, store,
request; mode = ‘readwrite’; store = db.getObjectStore(mode); request =
store.clear(); request.onsuccess = callback; }); }

1
2
3
4
5
6
7
8
9
deleteAll: function (callback) {
    db.open(function () {
        var mode, store, request;
        mode = ‘readwrite’;
        store = db.getObjectStore(mode);
        request = store.clear();
        request.onsuccess = callback;
    });
}

此地deleteAll函数负责打开数据库和访问object
store的叁个可写实例。一旦store可用,三个新的呼吁通过调用clear函数来创建。1旦clear操作成功,回调函数被实践。

举行用户界面特定代码

于今抱有特定于数据库的代码被封装在app.db模块中,用户界面特定代码能够使用此模块来与数据库交互。用户界面特定代码的完整清单(index.ui.js)能够在清单3中获得,完整的(index.html)页面包车型地铁HTML源代码能够在清单四中得到。

结论

乘机应用程序的须要的抓好,你会意识在客户端高效存款和储蓄多量的数码的优势。IndexedDB是足以在浏览器中平素利用且辅助异步事务的文书档案数据库完毕。即使浏览器的帮忙恐怕或不可能维持,但在适当的情形下,集成IndexedDB的Web应用程序具有强大的客户端数据的拜会能力。

在大部气象下,全体针对IndexedDB编写的代码是纯天然基于请求和异步的。官方正式有同步API,不过那种IndexedDB只适合web
worker的内外文中使用。那篇小说揭橥时,还一向不浏览器完结的壹起格式的IndexedDB
API。

必然要保险代码在别的函数域外对厂商特定的indexedDB, IDBTransaction, and
IDBKeyRange实例实行了规范化且使用了严厉格局。那允许你幸免浏览器错误,当在strict
mode下解析脚本时,它不会容许你对那多少个对象重新赋值。

你必须保障只传递正整数的本子号给数据库。传递到版本号的小数值会4舍5入。由此,假设你的数据库近年来版本壹,您准备访问1.2本子,upgrade-needed事件不会接触,因为版本号最后评估是同一的。

立刻实施函数表明式(IIFE)有时叫做区别的名字。有时能够观察如此的代码协会措施,它称作self-executing
anonymous functions(自实施匿名函数)或self-invoked anonymous
functions(自调用匿名函数)。为特别解释这几个名称相关的企图和含义,请阅读Ben
Alman的篇章Immediately Invoked Function Expression (IIFE) 。

Listing 1: Implementing the getAll function

JavaScript

getAll: function (callback) { db.open(function () { var store =
db.getObjectStore(), cursor = store.openCursor(), data = [];
cursor.onsuccess = function (e) { var result = e.target.result; if
(result && result !== null) { data.push(result.value);
result.continue(); } else { callback(data); } }; }); },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
getAll: function (callback) {
 
    db.open(function () {
 
        var
            store = db.getObjectStore(),
            cursor = store.openCursor(),
            data = [];
 
        cursor.onsuccess = function (e) {
 
            var result = e.target.result;
 
            if (result &&
                result !== null) {
 
                data.push(result.value);
                result.continue();
 
            } else {
 
                callback(data);
            }
        };
 
    });
},

Listing 2: Full source for database-specific code
(index.db.js)

JavaScript

// index.db.js ; window.indexedDB = window.indexedDB ||
window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction ||
window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange ||
window.msIDBKeyRange; (function(window){ ‘use strict’; var db = {
version: 1, // important: only use whole numbers! objectStoreName:
‘tasks’, instance: {}, upgrade: function (e) { var _db =
e.target.result, names = _db.objectStoreNames, name =
db.objectStoreName; if (!names.contains(name)) { _db.createObjectStore(
name, { keyPath: ‘id’, autoIncrement: true }); } }, errorHandler:
function (error) { window.alert(‘error: ‘ + error.target.code);
debugger; }, open: function (callback) { var request =
window.indexedDB.open( db.objectStoreName, db.version); request.onerror
= db.errorHandler; request.onupgradeneeded = db.upgrade;
request.onsuccess = function (e) { db.instance = request.result;
db.instance.onerror = db.errorHandler; callback(); }; }, getObjectStore:
function (mode) { var txn, store; mode = mode || ‘readonly’; txn =
db.instance.transaction( [db.objectStoreName], mode); store =
txn.objectStore( db.objectStoreName); return store; }, save: function
(data, callback) { db.open(function () { var store, request, mode =
‘readwrite’; store = db.getObjectStore(mode), request = data.id ?
store.put(data) : store.add(data); request.onsuccess = callback; }); },
getAll: function (callback) { db.open(function () { var store =
db.getObjectStore(), cursor = store.openCursor(), data = [];
cursor.onsuccess = function (e) { var result = e.target.result; if
(result && result !== null) { data.push(result.value);
result.continue(); } else { callback(data); } }; }); }, get: function
(id, callback) { id = parseInt(id); db.open(function () { var store =
db.getObjectStore(), request = store.get(id); request.onsuccess =
function (e){ callback(e.target.result); }; }); }, ‘delete’: function
(id, callback) { id = parseInt(id); db.open(function () { var mode =
‘readwrite’, store, request; store = db.getObjectStore(mode); request =
store.delete(id); request.onsuccess = callback; }); }, deleteAll:
function (callback) { db.open(function () { var mode, store, request;
mode = ‘readwrite’; store = db.getObjectStore(mode); request =
store.clear(); request.onsuccess = callback; }); } }; window.app =
window.app || {}; window.app.db = db; }(window));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// index.db.js
 
;
 
window.indexedDB = window.indexedDB ||
                   window.mozIndexedDB ||
                   window.webkitIndexedDB ||
                   window.msIndexedDB;
 
window.IDBTransaction = window.IDBTransaction ||
                   window.webkitIDBTransaction ||
                   window.msIDBTransaction;
 
window.IDBKeyRange = window.IDBKeyRange ||
                   window.webkitIDBKeyRange ||
                   window.msIDBKeyRange;
 
(function(window){
 
    ‘use strict’;
 
    var db = {
 
        version: 1, // important: only use whole numbers!
 
        objectStoreName: ‘tasks’,
 
        instance: {},
 
        upgrade: function (e) {
 
            var
                _db = e.target.result,
                names = _db.objectStoreNames,
                name = db.objectStoreName;
 
            if (!names.contains(name)) {
 
                _db.createObjectStore(
                    name,
                    {
                        keyPath: ‘id’,
                        autoIncrement: true
                    });
            }
        },
 
        errorHandler: function (error) {
            window.alert(‘error: ‘ + error.target.code);
            debugger;
        },
 
        open: function (callback) {
 
            var request = window.indexedDB.open(
                db.objectStoreName, db.version);
 
            request.onerror = db.errorHandler;
 
            request.onupgradeneeded = db.upgrade;
 
            request.onsuccess = function (e) {
 
                db.instance = request.result;
 
                db.instance.onerror =
                    db.errorHandler;
 
                callback();
            };
        },
 
        getObjectStore: function (mode) {
 
            var txn, store;
 
            mode = mode || ‘readonly’;
 
            txn = db.instance.transaction(
                [db.objectStoreName], mode);
 
            store = txn.objectStore(
                db.objectStoreName);
 
            return store;
        },
 
        save: function (data, callback) {
 
            db.open(function () {
 
                var store, request,
                    mode = ‘readwrite’;
 
                store = db.getObjectStore(mode),
 
                request = data.id ?
                    store.put(data) :
                    store.add(data);
 
                request.onsuccess = callback;
            });
        },
 
        getAll: function (callback) {
 
            db.open(function () {
 
                var
                    store = db.getObjectStore(),
                    cursor = store.openCursor(),
                    data = [];
 
                cursor.onsuccess = function (e) {
 
                    var result = e.target.result;
 
                    if (result &&
                        result !== null) {
 
                        data.push(result.value);
                        result.continue();
 
                    } else {
 
                        callback(data);
                    }
                };
 
            });
        },
 
        get: function (id, callback) {
 
            id = parseInt(id);
 
            db.open(function () {
 
                var
                    store = db.getObjectStore(),
                    request = store.get(id);
 
                request.onsuccess = function (e){
                    callback(e.target.result);
                };
            });
        },
 
        ‘delete’: function (id, callback) {
 
            id = parseInt(id);
 
            db.open(function () {
 
                var
                    mode = ‘readwrite’,
                    store, request;
 
                store = db.getObjectStore(mode);
 
                request = store.delete(id);
 
                request.onsuccess = callback;
            });
        },
 
        deleteAll: function (callback) {
 
            db.open(function () {
 
                var mode, store, request;
 
                mode = ‘readwrite’;
                store = db.getObjectStore(mode);
                request = store.clear();
 
                request.onsuccess = callback;
            });
 
        }
    };
 
    window.app = window.app || {};
    window.app.db = db;
 
}(window));

Listing 3: Full source for user interface-specific code
(index.ui.js)

JavaScript

// index.ui.js ; (function ($, Modernizr, app) { ‘use strict’;
$(function(){ if(!Modernizr.indexeddb){
$(‘#unsupported-message’).show(); $(‘#ui-container’).hide(); return; }
var $deleteAllBtn = $(‘#delete-all-btn’), $titleText =
$(‘#title-text’), $notesText = $(‘#notes-text’), $idHidden =
$(‘#id-hidden’), $clearButton = $(‘#clear-button’), $saveButton =
$(‘#save-button’), $listContainer = $(‘#list-container’),
$noteTemplate = $(‘#note-template’), $emptyNote = $(‘#empty-note’);
var addNoTasksMessage = function(){ $listContainer.append(
$emptyNote.html()); }; var bindData = function (data) {
$listContainer.html(”); if(data.length === 0){ addNoTasksMessage();
return; } data.forEach(function (note) { var m = $noteTemplate.html(); m
= m.replace(/{ID}/g, note.id); m = m.replace(/{TITLE}/g, note.title);
$listContainer.append(m); }); }; var clearUI = function(){
$titleText.val(”).focus(); $notesText.val(”); $idHidden.val(”); }; //
select individual item $listContainer.on(‘click’, ‘a[data-id]’,
function (e) { var id, current; e.preventDefault(); current =
e.currentTarget; id = $(current).attr(‘data-id’); app.db.get(id,
function (note) { $titleText.val(note.title); $notesText.val(note.text);
$idHidden.val(note.id); }); return false; }); // delete item
$listContainer.on(‘click’, ‘i[data-id]’, function (e) { var id,
current; e.preventDefault(); current = e.currentTarget; id =
$(current).attr(‘data-id’); app.db.delete(id, function(){
app.db.getAll(bindData); clearUI(); }); return false; });
$clearButton.click(function(e){ e.preventDefault(); clearUI(); return
false; }); $saveButton.click(function (e) { var title =
$titleText.val(); if (title.length === 0) { return; } var note = {
title: title, text: $notesText.val() }; var id = $idHidden.val(); if(id
!== ”){ note.id = parseInt(id); } app.db.save(note, function(){
app.db.getAll(bindData); clearUI(); }); }); $deleteAllBtn.click(function
(e) { e.preventDefault(); app.db.deleteAll(function () {
$listContainer.html(”); addNoTasksMessage(); clearUI(); }); return
false; }); app.db.errorHandler = function (e) { window.alert(‘error: ‘ +
e.target.code); debugger; }; app.db.getAll(bindData); }); }(jQuery,
Modernizr, window.app));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// index.ui.js
 
;
 
(function ($, Modernizr, app) {
 
    ‘use strict’;
 
    $(function(){
 
        if(!Modernizr.indexeddb){
            $(‘#unsupported-message’).show();
            $(‘#ui-container’).hide();
            return;
        }
 
        var
          $deleteAllBtn = $(‘#delete-all-btn’),
          $titleText = $(‘#title-text’),
          $notesText = $(‘#notes-text’),
          $idHidden = $(‘#id-hidden’),
          $clearButton = $(‘#clear-button’),
          $saveButton = $(‘#save-button’),
          $listContainer = $(‘#list-container’),
          $noteTemplate = $(‘#note-template’),
          $emptyNote = $(‘#empty-note’);
 
        var addNoTasksMessage = function(){
            $listContainer.append(
                $emptyNote.html());
        };
 
        var bindData = function (data) {
 
            $listContainer.html(”);
 
            if(data.length === 0){
                addNoTasksMessage();
                return;
            }
 
            data.forEach(function (note) {
              var m = $noteTemplate.html();
              m = m.replace(/{ID}/g, note.id);
              m = m.replace(/{TITLE}/g, note.title);
              $listContainer.append(m);
            });
        };
 
        var clearUI = function(){
            $titleText.val(”).focus();
            $notesText.val(”);
            $idHidden.val(”);
        };
 
        // select individual item
        $listContainer.on(‘click’, ‘a[data-id]’,
 
            function (e) {
 
                var id, current;
 
                e.preventDefault();
 
                current = e.currentTarget;
                id = $(current).attr(‘data-id’);
 
                app.db.get(id, function (note) {
                    $titleText.val(note.title);
                    $notesText.val(note.text);
                    $idHidden.val(note.id);
                });
 
                return false;
            });
 
        // delete item
        $listContainer.on(‘click’, ‘i[data-id]’,
 
            function (e) {
 
                var id, current;
 
                e.preventDefault();
 
                current = e.currentTarget;
                id = $(current).attr(‘data-id’);
 
                app.db.delete(id, function(){
                    app.db.getAll(bindData);
                    clearUI();
                });
 
                return false;
        });
 
        $clearButton.click(function(e){
            e.preventDefault();
            clearUI();
            return false;
        });
 
        $saveButton.click(function (e) {
 
            var title = $titleText.val();
 
            if (title.length === 0) {
                return;
            }
 
            var note = {
                title: title,
                text: $notesText.val()
            };
 
            var id = $idHidden.val();
 
            if(id !== ”){
                note.id = parseInt(id);
            }
 
            app.db.save(note, function(){
                app.db.getAll(bindData);
                clearUI();
            });
        });
 
        $deleteAllBtn.click(function (e) {
 
            e.preventDefault();
 
            app.db.deleteAll(function () {
                $listContainer.html(”);
                addNoTasksMessage();
                clearUI();
            });
 
            return false;
        });
 
        app.db.errorHandler = function (e) {
            window.alert(‘error: ‘ + e.target.code);
            debugger;
        };
 
        app.db.getAll(bindData);
 
    });
 
}(jQuery, Modernizr, window.app));

Listing 3: Full HTML source (index.html)

JavaScript

<!doctype html> <html lang=”en-US”> <head> <meta
charset=”utf-8″> <meta http-equiv=”X-UA-Compatible”
content=”IE=edge”> <title>Introduction to
IndexedDB</title> <meta name=”description”
content=”Introduction to IndexedDB”> <meta name=”viewport”
content=”width=device-width, initial-scale=1″> <link
rel=”stylesheet”
href=”//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css”>
<link rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/css/font-awesome.min.css” > <link
rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/FontAwesome.otf” > <link
rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.eot” > <link
rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.svg” > <link
rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.ttf” > <link
rel=”stylesheet” href=”//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.woff” > <style>
h1 { text-align: center; color:#999; } ul li { font-size: 1.35em;
margin-top: 1em; margin-bottom: 1em; } ul li.small { font-style: italic;
} footer { margin-top: 25px; border-top: 1px solid #eee; padding-top:
25px; } i[data-id] { cursor: pointer; color: #eee; }
i[data-id]:hover { color: #c75a6d; } .push-down { margin-top: 25px; }
#save-button { margin-left: 10px; } </style> <script
src=”//cdnjs.cloudflare.com/ajax/libs/modernizr /2.8.2/modernizr.min.js”
></script> </head> <body class=”container”>
<h1>Tasks</h1> <div id=”unsupported-message” class=”alert
alert-warning” style=”display:none;”> <b>Aww snap!</b>
Your browser does not support indexedDB. </div> <div
id=”ui-container” class=”row”> <div class=”col-sm-3″> <a
href=”#” id=”delete-all-btn” class=”btn-xs”> <i class=”fa
fa-trash-o”></i> Delete All</a> <hr/> <ul
id=”list-container” class=”list-unstyled”></ul> </div>
<div class=”col-sm-8 push-down”> <input type=”hidden”
id=”id-hidden” /> <input id=”title-text” type=”text”
class=”form-control” tabindex=”1″ placeholder=”title” autofocus
/><br /> <textarea id=”notes-text” class=”form-control”
tabindex=”2″ placeholder=”text”></textarea> <div
class=”pull-right push-down”> <a href=”#” id=”clear-button”
tabindex=”4″>Clear</a> <button id=”save-button” tabindex=”3″
class=”btn btn-default btn-primary”> <i class=”fa
fa-save”></i> Save</button> </div> </div>
</div> <footer class=”small text-muted text-center”>by <a
href=”http://craigshoemaker.net” target=”_blank”>Craig
Shoemaker</a> <a href=”http://twitter.com/craigshoemaker
target=”_blank”> <i class=”fa fa-twitter”></i></a>
</footer> <script id=”note-template” type=”text/template”>
<li> <i data-id=”{ID}” class=”fa fa-minus-circle”></i>
<a href=”#” data-id=”{ID}”>{TITLE}</a> </li>
</script> <script id=”empty-note” type=”text/template”>
<li class=”text-muted small”>No tasks</li> </script>
<script src=”//ajax.googleapis.com/ajax/libs
/jquery/1.11.1/jquery.min.js”></script> <script
src=”index.db.js” type=”text/javascript”></script> <script
src=”index.ui.js” type=”text/javascript”></script>
</body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!doctype html>
<html lang="en-US">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Introduction to IndexedDB</title>
        <meta name="description"
              content="Introduction to IndexedDB">
        <meta name="viewport"
              content="width=device-width, initial-scale=1">
        <link rel="stylesheet"
              href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/css/font-awesome.min.css" >
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/FontAwesome.otf" >
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.eot" >
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.svg" >
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.ttf" >
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs
/font-awesome/4.1.0/fonts/fontawesome-webfont.woff" >
        <style>
            h1 {
                text-align: center;
                color:#999;
            }
 
            ul li {
                font-size: 1.35em;
                margin-top: 1em;
                margin-bottom: 1em;
            }
 
            ul li.small {
                font-style: italic;
            }
 
            footer {
                margin-top: 25px;
                border-top: 1px solid #eee;
                padding-top: 25px;
            }
 
            i[data-id] {
                cursor: pointer;
                color: #eee;
            }
 
            i[data-id]:hover {
                color: #c75a6d;
            }
 
            .push-down {
                margin-top: 25px;
            }
 
            #save-button {
                margin-left: 10px;
            }
        </style>
        <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr
/2.8.2/modernizr.min.js" ></script>
    </head>
    <body class="container">
        <h1>Tasks</h1>
        <div id="unsupported-message"
             class="alert alert-warning"
             style="display:none;">
            <b>Aww snap!</b> Your browser does not support indexedDB.
        </div>
        <div id="ui-container" class="row">
            <div class="col-sm-3">
 
                <a href="#" id="delete-all-btn" class="btn-xs">
                    <i class="fa fa-trash-o"></i> Delete All</a>
 
                <hr/>
 
                <ul id="list-container" class="list-unstyled"></ul>
 
            </div>
            <div class="col-sm-8 push-down">
 
                <input type="hidden" id="id-hidden" />
 
                <input
                       id="title-text"
                       type="text"
                       class="form-control"
                       tabindex="1"
                       placeholder="title"
                       autofocus /><br />
 
                <textarea
                          id="notes-text"
                          class="form-control"
                          tabindex="2"
                          placeholder="text"></textarea>
 
                <div class="pull-right push-down">
 
                    <a href="#" id="clear-button" tabindex="4">Clear</a>
 
                    <button id="save-button"
                            tabindex="3"
                            class="btn btn-default btn-primary">
                                <i class="fa fa-save"></i> Save</button>
                </div>
            </div>
        </div>
        <footer class="small text-muted text-center">by
            <a href="http://craigshoemaker.net" target="_blank">Craig Shoemaker</a>
            <a href="http://twitter.com/craigshoemaker" target="_blank">
                <i class="fa fa-twitter"></i></a>
        </footer>
        <script id="note-template" type="text/template">
            <li>
                <i data-id="{ID}" class="fa fa-minus-circle"></i>
                <a href="#" data-id="{ID}">{TITLE}</a>
            </li>
        </script>
        <script id="empty-note" type="text/template">
            <li class="text-muted small">No tasks</li>
        </script>
        <script src="//ajax.googleapis.com/ajax/libs
/jquery/1.11.1/jquery.min.js"></script>
        <script src="index.db.js" type="text/javascript"></script>
        <script src="index.ui.js" type="text/javascript"></script>
    </body>
</html>

赞 1 收藏
评论

有关笔者:cucr

图片 8

网易博客园:@hop_ping
个人主页
·
笔者的小说
·
17

图片 9

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图