一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
indexdb VS localstorage
LocalStorage
是用 key-value
键值模式存储数据,它存储的数据都是字符串形式。,就是专门为小数量
数据设计的,所以它的 api 设计为同步
的。
对于简单的数据,你应该继续使用 localstorage
,但当你希望存储大量数据时,IndexedDB
会明显的更适合,IndexedDB
能提供你更为复杂的查询数据的方式。
indexDB特点
-
键值对储存
: IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。 -
异步
: IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与LocalStorage 形成对比,后者的操作是同步的
。异步设计是为了防止大量数据的读写,拖慢网页的表现。 -
支持事务
: IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。 -
同源限制
: IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。 -
储存空间大
: IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限
。 -
支持二进制储存
: IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
简单DEMO
<form id="form">
<p>项目名称:<input required name="name" autocomplete="off" required></p>
<p>开始时间:<input type="date" value="2017-07-16" name="begin" required></p>
<p>预计结束:<input type="date" value="2057-07-16" name="end" required></p>
<p>参与人员:<input name="person" placeholder="多人空格分隔" required autocomplete="off"></p>
<p>补充说明:<textarea rows="5" placeholder="非必填" name="remark"></textarea></p>
<p><input type="submit" value="确定创建"></p>
</form>
<div id="result" class="result">
<table>
<thead>
<tr>
<th>项目名称</th>
<th>开始时间</th>
<th>结束时间</th>
<th>参与人员</th>
<th>补充说明</th>
<th width="30">操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div id="status" class="status">加载中...</div>
</div>
<!-- 列表数据模板 -->
<script id="tplList" type="text/template">
<tr>
<td data-key="name" data-id="$id$" contenteditable="plaintext-only">$name$</td>
<td data-key="begin" data-id="$id$" contenteditable="plaintext-only">$begin$</td>
<td data-key="end" data-id="$id$" contenteditable="plaintext-only">$end$</td>
<td data-key="person" data-id="$id$" contenteditable="plaintext-only">$person$</td>
<td data-key="remark" data-id="$id$" contenteditable="plaintext-only">$remark$</td>
<td><a href="javascript:" role="button" class="jsListDel" data-id="$id$">删除</a></td>
</tr></script>
JS代码:
- 打开数据库:
window.indexedDB.open(dbName, version)
(function () {
// 元素们
var eleForm = document.querySelector('#form');
var eleTbody = document.querySelector('#result tbody');
var eleStatus = document.getElementById('status');
// 模板字符内容
var strTplList = document.getElementById('tplList').innerHTML;
var logError = function (error) {
eleStatus.style.display = 'block';
eleStatus.innerHTML = '<span class="error">'+ error +'</span>';
}, logInfo = function (info) {
eleStatus.style.display = 'block';
eleStatus.innerHTML = '<span class="info">'+ info + '</span>';
};
// 简易模板方法
String.prototype.temp = function(obj) {
return this.replace(/$\w+$/gi, function(matchs) {
return obj[matchs.replace(/$/g, "")] || '';
});
};
// 本演示使用的数据库名称
var dbName = 'project';
// 版本
var version = 1;
// 数据库数据结果
var db;
// 打开数据库
var DBOpenRequest = window.indexedDB.open(dbName, version);
// 如果数据库打开失败
DBOpenRequest.onerror = function(event) {
logError('数据库打开失败');
};
DBOpenRequest.onsuccess = function(event) {
// 存储数据结果
db = DBOpenRequest.result;
// 显示数据
method.show();
};
// 下面事情执行于:数据库首次创建版本,或者window.indexedDB.open传递的新版本(版本数值要比现在的高)
DBOpenRequest.onupgradeneeded = function(event) {
var db = event.target.result;
db.onerror = function(event) {
logError('数据库打开失败');
};
// 创建一个数据库存储对象
var objectStore = db.createObjectStore(dbName, {
keyPath: 'id',
autoIncrement: true
});
// 定义存储对象的数据项
objectStore.createIndex('id', 'id', {
unique: true
});
objectStore.createIndex('name', 'name');
objectStore.createIndex('begin', 'begin');
objectStore.createIndex('end', 'end');
objectStore.createIndex('person', 'person');
objectStore.createIndex('remark', 'remark');
};
var method = {
add: function (newItem) {
var transaction = db.transaction([dbName], "readwrite");
// 打开已经存储的数据对象
var objectStore = transaction.objectStore(dbName);
// 添加到数据对象中
var objectStoreRequest = objectStore.add(newItem);
objectStoreRequest.onsuccess = function(event) {
method.show();
};
},
edit: function (id, data) {
// 编辑数据
var transaction = db.transaction([dbName], "readwrite");
// 打开已经存储的数据对象
var objectStore = transaction.objectStore(dbName);
// 获取存储的对应键的存储对象
var objectStoreRequest = objectStore.get(id);
// 获取成功后替换当前数据
objectStoreRequest.onsuccess = function(event) {
// 当前数据
var myRecord = objectStoreRequest.result;
// 遍历替换
for (var key in data) {
if (typeof myRecord[key] != 'undefined') {
myRecord[key] = data[key];
}
}
// 更新数据库存储数据
objectStore.put(myRecord);
};
},
del: function (id) {
// 打开已经存储的数据对象
var objectStore = db.transaction([dbName], "readwrite").objectStore(dbName);
// 直接删除
var objectStoreRequest = objectStore.delete(id);
// 删除成功后
objectStoreRequest.onsuccess = function() {
method.show();
};
},
show: function () {
// 最终要展示的HTML数据
var htmlProjectList = '';
// 打开对象存储,获得游标列表
var objectStore = db.transaction(dbName).objectStore(dbName);
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
// 如果游标没有遍历完,继续下面的逻辑
if (cursor) {
htmlProjectList = htmlProjectList + strTplList.temp(cursor.value);
// 继续下一个游标项
cursor.continue();
// 如果全部遍历完毕
} else {
logInfo('');
eleTbody.innerHTML = htmlProjectList;
if (htmlProjectList == '') {
logInfo('暂无数据');
}
}
}
}
};
// 表单提交新增数据
eleForm.addEventListener('submit', function (event) {
event.preventDefault();
var formData = {};
[].slice.call(this.querySelectorAll('input,textarea')).forEach(function (ele) {
if (ele.name) {
formData[ele.name] = ele.value;
}
});
// 添加新的数据
method.add(formData);
this.reset();
});
// 编辑事件
eleTbody.addEventListener('focusout', function (event) {
var eleTd = event.target;
// 获取id,也就是获得主键
var id = eleTd && eleTd.getAttribute('data-id');
if (!id || !/td/.test(eleTd.tagName)) { return; }
// 这是要替换的数据
var data = {
id: id * 1
};
// 获得现在的数据
[].slice.call(eleTd.parentElement.querySelectorAll('td[data-key]')).forEach(function (td) {
var key = td.getAttribute('data-key');
var value = td.innerText || td.textContent || '';
data[key] = value;
});
// 更新本地数据库
method.edit(id, data);
});
// 删除事件
eleTbody.addEventListener('click', function (event) {
var eleBtn = event.target, id = '';
if (eleBtn && eleBtn.classList.contains('jsListDel') && (id = eleBtn.getAttribute('data-id'))) {
method.del(id * 1);
event.preventDefault();
}
});
})();