菜单

IndexedDB数据库

2019年3月26日 - JavaScript

前端的数据库:IndexedDB入门

2014/12/27 · 未分类 · IndexedDB

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

应用程序须求多少。对绝超越四分之二Web应用程序来说,数据在劳动器端组织和保管,客户端通过网络请求获取。随着浏览器变得尤为有力量,因而可挑选在浏览器存款和储蓄和操纵应用程序数据。

正文向您介绍名为IndexedDB的浏览器端文书档案数据库。使用lndexedDB,你能够透过惯于在服务器端数据库差不离同样的措施开创、读取、更新和删除大批量的笔录。请使用本文中可工作的代码版本去体会,完整的源代码能够透过GitHub库找到。

读到本课程的终极时,你将熟谙IndexedDB的基本概念以及如何贯彻贰个用到IndexedDB执行总体的CRUD操作的模块化JavaScript应用程序。让大家多少亲近IndexedDB并起初吧。

什么是IndexedDB

诚如的话,有三种不一样类型的数据库:关系型和文书档案型(也叫做NoSQL或对象)。关全面据库如SQL
Server,MySQL,Oracle的多寡存款和储蓄在表中。文书档案数据库如MongoDB,CouchDB,Redis将数据集作为个体对象存款和储蓄。IndexedDB是一个文书档案数据库,它在完全内放置浏览器中的几个沙盒环境中(强制依据(浏览器)同源策略)。图1来得了IndexedDB的数码,展现了数据库的布局

图片 1

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

凡事的IndexedDB API请参见完整文书档案

介绍

IndexedDB就是叁个数据库
其最大的特征是:
运用对象保存数据,而不是行使表来保存数据,同时,它是异步的

规划规范

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

使用方法

目的仓库

object
store是IndexedDB数据库的基础。就算您利用过关周到据库,平常能够将object
store等价于四个数码库表。Object
stores包涵一个或八个目录,在store中遵守一对键/值操作,那提供一种高效稳定数据的主意。

当您布署一个object
store,你不能够不为store选取三个键。键在store中能够以“in-line”或“out-of-line”的主意存在。in-line键通过在数额对象上引用path来维系它在object
store的唯一性。为了求证那或多或少,想想1个归纳电子邮件地址属性Person对象。您能够配备你的store使用in-line键emailAddress,它能确认保证store(持久化对象中的数据)的唯一性。其余,out-of-line键通过单独于数据的值识别唯一性。在那种状态下,你能够把out-of-line键比作2个整数值,它(整数值)在关周详据库中出任记录的主键。

图1显得了职务数据保存在任务的object
store,它利用in-line键。在这些案例中,键对应于对象的ID值。

连日数据库

要接纳它必须先打开,通过 indexDB.open(name, version)主意打开叁个数据库

基于事务

差别于一些观念的关周密据库的贯彻,每贰个对数据库操作是在二个作业的上下文中执行的。事务限制2回影响1个或五个object
stores,你通过传播2个object store名字的数组到开创工作限制的函数来定义。

开创工作的第三个参数是业务形式。当呼吁1个事务时,必须控制是奉公守法只读仍旧读写方式请求访问。事务是能源密集型的,所以一旦您不须求更改data
store中的数据,你只需求以只读情势对object stores集合实行呼吁访问。

清单2示范了什么选取合适的方式创制三个作业,并在那片小说的 Implementing
Database-Specific Code
 部分举行了详尽座谈。

indexDB.open()方法的规律

分成两种情况:
1. 传诵的数据库不存在
当传入的数据库不存在时,该措施就会创制2个名为name的数据库,并打开它,此时,会先触发upgradeneeded事件;调用该函数会重回1个IDBRequest对象,能够在该对象上添加onsuccess事件onerror事件
注意:当打开多少个不设有的数据库时会触发upgradeneeded事件,那是触发该事件的一种途径,为何会触发该事件呢?该事件有怎么着意义?留个难题在此时,等会解答。

2. 传播的数据仓库储存在
那边分为二种处境:

依照请求

以至于那里,有一个屡屡出现的宗旨,您大概早就注意到。对数据库的每趟操作,描述为通过四个呼吁打开数据库,访问三个object
store,再持续。IndexedDB
API天生是依照请求的,这也是API异步性子提示。对于你在数据库执行的历次操作,你无法不首先为这些操作创立2个请求。当呼吁完毕,你能够响应由请求结果爆发的风浪和不当。

正文完成的代码,演示了何等采用请求打开数据库,创制三个政工,读取object
store的始末,写入object store,清空object store。

upgradeneeded事件

触发该事件的条件:当打开的数据库不设有,或许传播的数据库版本version高于当前版本,则会触发该事件

upgradeneeded事件的机能:当打开了一个数据库之后,须要开拓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使用事件生命周期管理数据库的开辟和安插操作。图2演示了三个开拓的恳求在自然的环境下发出upgrade
need事件。

图片 2

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

所有与数据库的并行开始于四个打开的央求。试图打开数据库时,您必须传递1个被呼吁数据库的本子号的整数值。在开拓请求时,浏览器相比较你传入的用于打开请求的版本号与事实上数据库的版本号。倘诺所请求的版本号高于浏览器中当前的版本号(或然今后并未存在的数据库),upgrade
needed事件触发。在uprade
need事件期间,你有机遇通过抬高或移除stores,键和索引来操纵object stores。

若果所请求的数据库版本号和浏览器的最近版本号同样,或许升级进度做到,1个打开的数据库将赶回给调用者。

积存数据

仓库储存数据有二种格局: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通过荒谬冒泡效果来帮忙跟踪和管制不当。假诺3个特定的乞求碰着错误,你能够尝尝在呼吁对象上处理错误,只怕你能够允许错误通过调用栈冒泡向上传递。这几个冒泡本性,使得你不须求为各样请求完成特定错误处理操作,而是能够选用只在三个更高级别上添加错误处理,它给你1个机遇,保持您的错误处理代码简洁。本文中落实的例证,是在一个高级别处理错误,以便更细粒度操作发生的别样不当冒泡到通用的错误处理逻辑。

业务和查询操作数据

最简便易行的开创工作的章程是:
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的支撑在连续加强,选拔率并不是大家所企望的那么普遍。图3来得了caniuse.com网站的告知,扶助IndexedDB的为66%多一丢丢。最新版本的银狐,Chrome,Opera,Safar,iOS
Safari,和Android完全补助IndexedDB,Internet
Explorer和小米部分援助。尽管那几个列表的维护者是冲动的,但它没有报告全数传说。

图片 3

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

只有可怜新本子的Safari和iOS Safari
援救IndexedDB。据caniuse.com展现,那只占大约0.01%的满世界浏览器接纳。IndexedDB不是一个您以为可以理所当然得到援救的现世Web
API,不过你将飞快会那样认为。

运用游标查询数据

动用工作能够直接通过
已知的键检索单个对象。而在急需摸索七个对象时,则要求在工作内创制游标。

游标并不会提早收集结果,游标先指向结果中的第③项,在接受查找下一项的通令时,才会针对下一项

如下:

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实际上是二个扬弃的技艺,为何还要提它呢?有趣的是,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’;
// 创造3个数量
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.”)
}

// 3
是确立的数据库版本,假诺名为MyTestDatabase的数据库不存在,就会创立该数据库,然后
onupgradeneeded 事件会被触发;
// 要是数据仓库储存在,不过对版本升级了,也会触发onupgradeneeded事件,
// 注意:版本号是一个 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中。
//
在该处理程序中,数据库已经有所先前版本的对象存款和储蓄,由此无需再次制造那些目标存款和储蓄,只须要创建任何大家须求的对象存款和储蓄,也许
//
从先前版本中删除不在须求的靶子存款和储蓄。若是要求转移当前目的存储,则必须先删除旧的指标存款和储蓄,然后在运用新的选项创设。
// 删除旧的靶子存款和储蓄,在其上的新闻都会被剔除;
//
注意:该事件是唯一三个可见对数据库举行操作的地点,在该事件之中,你对目的存储实行删减、修改或移除索引
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’); //
创立一个事物, 并定义该业务的操作为 “readonly”
let store = transaction.objectStore(‘customers’).get(‘444-44-4444’); //
使用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是不是合乎本身的应用程序?“像以前一致,答案是迟早的:“视意况而定。“首先当您准备在客户端保存数据时,你会设想HTML5当地存款和储蓄。本地存款和储蓄得到大面积浏览器的支撑,有格外简单使用的API。简单有其优势,但其劣势是无法支撑复杂的摸索策略,存款和储蓄大量的多寡,并提供工作帮衬。

IndexedDB是一个数据库。所以,当您想为客户端做出决定,考虑你什么样在服务端选取一个持久化介质的数据库。你可能会问自个儿有个别问题来辅助控制客户端数据库是不是吻合你的应用程序,包罗:

如果你对在那之中的别的难题回复了“是的”,很有可能,IndexedDB是你的应用程序的叁个很好的候选。

使用IndexedDB

到现在,你曾经有机遇纯熟了一些的完全概念,下一步是从头落到实处基于IndexedDB的应用程序。第2个步骤须要统一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开端工作。

行使概述

在本教程中,您将学习如何创制贰个利用IndexedDB存储数据的模块化JavaScript应用程序。为了打探应用程序是何等工作的,参考图4,它描述了职分应用程序处于空白状态。从此处您可以为列表添加新职分。图5出示了录入了多少个职分到系统的画面。图6显得怎么删除二个任务,图7突显了正在编写制定任务时的应用程序。

图片 4

图4:空白的任务应用程序

图片 5

图5:义务列表

图片 6

图6:删除职分

图片 7

图7:编辑职责
近来您纯熟的应用程序的作用,下一步是发端为网站铺设基础。

铺设基础

以此例子从落成如此1个模块开头,它负责从数据库读取数据,插入新的目的,更新现有对象,删除单个对象和提供在1个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));

用如此的构造,能够使那些应用程序的装有逻辑封装在1个名为app的单对象上。其余,数据库相关的代码在一个誉为db的app子对象上。

以此模块的代码应用IIFE,通过传递window对象来保管模块的确切限制。使用use
strict确定保障这么些函数的代码函数是遵守(javascript严苛形式)严厉编写翻译规则。db对象作为与数据库交互的拥有函数的首要容器。最终,window对象检查app的实例是或不是存在,假使存在,模块使用当前实例,假使不存在,则开创二个新对象。一旦app对象成功再次回到或创建,db对象附加到app对象。

正文的其他部分将代码添加到db对象内(在implementation
here会
评说),为应用程序提供一定于数据库的逻辑。因而,如你所见本文前面的局地中定义的函数,想想父db对象活动,但全数别的职能都以db对象的成员。完整的数据库模块列表见清单2。

Implementing Database-Specific Code

对数据库的每一个操作关联着二个先决条件,即有三个开辟的数据库。当数据库正在被打开时,通过检查数据库版本来判断数据库是不是要求任何变更。下边包车型客车代码展现了模块怎么样跟踪当前版本,object
store名、某成员(保存了一旦数据库打开请求达成后的数据库当前实例)。

JavaScript

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

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

在此间,数据库打开请求发生时,模块请求版本1数据库。要是数据库不设有,大概版本小于1,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,您能够很不难地看到别的不当(当她们爆发时)。当你准备在生养条件使用那些模块,您供给在这些函数中完毕部分错误处理代码来和您的应用程序的上下文打交道。

今天基础实现了,这一节的其他部分将演示怎样落实对数据库执行一定操作。第三个供给检查的函数是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的名字到数组中。事务函数的第二个参数是2个情势。

一经事情请求可用,您就能够通过传递须求的object
store名字来调用objectStore函数以取得object
store实例的访问权。这些模块的别的函数使用getObjectStore来得到object
store的访问权。

下2个落到实处的函数是save函数,执行插入或更新操作,它依照传入的数量是不是有3个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的3个可写实例。然后,检查数据对象的ID成员是不是留存。假如存在ID值,数据必须革新,put函数被调用,它成立持久化请求。不然,若是ID不设有,这是新数据,add请求重临。最终,不管put只怕add
请求是或不是实施了,success事件处理程序供给安装在回调函数上,来报告调用脚本,一切进展顺利。

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

在store访问数据时,游标遍历数据库中的每条记下,会触发onsuccess事件处理程序。当每条记下走访时,store的数量能够透过e.target.result事件参数得到。尽管事实上数据从target.result的value属性中获得,首先必要在总括访问value属性前确认保障result是1个可行的值。假诺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参数的值转换为三个平头。取决于函数被调用时,字符串或整数都恐怕传递给函数。那么些完结跳过了对如果所给的字符串无法转换来整数该如何做的景色的处理。一旦四个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和2个回调函数。为了维持那些达成简单,delete函数约定id的值为整数。您能够选拔创制一个更结实的落到实处来处理id值不可能分析成整数的荒谬例子的回调,但为了指引原因,代码示例是明知故犯的。

假诺id值能确认保障转换来一个整数,数据库被打开,3个可写的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函数来创制。一旦clear操作成功,回调函数被实施。

进行用户界面特定代码

现行反革命拥有特定于数据库的代码被封装在app.db模块中,用户界面特定代码能够应用此模块来与数据库交互。用户界面特定代码的完全清单(index.ui.js)能够在清单3中获得,完整的(index.html)页面的HTML源代码能够在清单4中赢得。

结论

乘机应用程序的急需的提高,你会发未来客户端高效存款和储蓄多量的数额的优势。IndexedDB是足以在浏览器中一贯运用且帮忙异步事务的文书档案数据库完毕。就算浏览器的辅助大概否维持,但在适当的图景下,集成IndexedDB的Web应用程序具有强大的客户端数据的造访能力。

在大部分状态下,全体针对IndexedDB编写的代码是原始基于请求和异步的。官方正规有同步API,可是那种IndexedDB只适合web
worker的上下文中使用。那篇小说揭橥时,还不曾浏览器达成的一块格式的IndexedDB
API。

早晚要保管代码在任何函数域外对厂商特定的indexedDB, IDBTransaction, and
IDBKeyRange实例实行了规范化且使用了严酷方式。那允许你幸免浏览器错误,当在strict
mode下解析脚本时,它不会同意你对那三个对象重新赋值。

你必须保障只传递正整数的本子号给数据库。传递到版本号的小数值会四舍五入。由此,如若你的数据库如今版本1,您准备访问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地图