购物网站制作怎么做,wordpress跳转到微信,做网站很简单,蓝海国际版网站建设系统前言
相信 IndexedDB 大家都有过了解#xff0c;但是不一定每个人都有过实践#xff0c;并且其中涉及到事务、游标等概念#xff0c;会导致在初次使用时会有些不适应#xff0c;那么本文会通过 IndexedDB 实现分页查询的形式进行实践#xff0c;在开始之前#xff0c;可…前言
相信 IndexedDB 大家都有过了解但是不一定每个人都有过实践并且其中涉及到事务、游标等概念会导致在初次使用时会有些不适应那么本文会通过 IndexedDB 实现分页查询的形式进行实践在开始之前可以尝试思考一下浏览器的客户端存储你都了解哪些呢
其实客户端存储分为下面几类 cookie Web Storage sessionStoragelocalStorage IndexDB
cookie
cookies 的特点
cookie 是与特定域进行绑定的所有 cookie 都会作为请求头部由浏览器发送给服务器大多数浏览器对 1个域 下所有 cookie 的限制是不超过 4096 Byte即 4 KB上下可以有 1 Byte 的误差
假如 cookie 中保存大量信息那么可能会影响特定域下浏览器请求的性能因为保存的 cookie 越大请求完成的时间就越长由于以上的这些限制 cookie 只适合保存服务器必要的信息.
Web Storage
Web Storage 的目的是为了解决客户端需要使用 cookie 存储一些不需要频繁发送回服务器的数据.
sessionStorage
sessionStorage 的特点
只存储会话数据即数据只会存储到当前设置存储的 tab 页面被关闭或者是浏览器关闭只能存储字符串类型数据不能存储结构化数据存储的数据不受页面刷新影响可在浏览器崩溃并重启后恢复大多数浏览器限制 1个源 只能存储 5MB
localStorage
localStorage 的特点
存储的数据会一直保留直到通过 JavaScript 删除或者用户清除浏览器缓存只能存储字符串类型数据不能存储结构化数据存储的数据不受页面刷新影响也不会因关闭窗口、标签页或重新启动浏览器而丢失大多数浏览器限制 1个源 只能存储 5MB
IndexDB
IndexedDBIndexed Database API 是浏览器中 存储结构化数据 的一个方案用于代替目前已废弃的 Web SQL Database API.
其中 API 的设计基本上是 异步的大多数操作以请求的形式 异步执行产生成功的结果或错误都有对应的 onerror 和 onsuccess 事件处理程序来确定输出.
IndexedDB 的特点
能够存储结构化数据IndexedDB 数据库是与 页面源 绑定的不能跨域共享大小限制 Chrome 限制是每个源 5MBFirefox 限制是每个源 50MBFirefox移动版 限制每个源 5MB 若超出则请求用户许可
从以上可以看出 IndexedDB 的限制其实 Web Storage 一样. 页面源源 协议 域 端口 IndexedDB
数据库
IndexedDB 数据库是类似于 MySQL 或 Web SQL Database 的数据库它使用对象存储数据而不是使用表格并且属于 NoSQL 的风格.
建立数据库连接 —— indexedDB.open() indexedDB.open(name, version) 其中 name 为数据库名称version 为数据库版本且版本只能为整数 通过 indexedDB.open(name, version) 使用数据库 如果给定名称的数据库 已存在则会发送一个 打开请求如果 不存在则会发送 创建 并 打开 这个数据库的请求异步执行返回 IDBRequest 实例需要监听 onerror 和 onsuccess 事件
如下将创建一个名为 test 的数据库 let db, request, version 1;
request indexedDB.open(test, version);
request.onerror (event) alert(Failed to open: ${event.target.errorCode});
request.onsuccess (event) {db event.target.result;
};对象存储 —— request.onupgradeneeded()
数据库 版本发生变化 或 创建新数据库时 就会触发 onupgradeneeded 事件此时需要指定或换修改 数据库模式 —— 包括数据库中的 对象存储 和对象 存储结构
如下将在 test 数据库下创建名为 productions 的对象存储模式 // 需要存储的对象
let production {id: 20220128,name: 产品xxx,
}// 指定对象存储的模式
request.onupgradeneeded (event) {const db event.target.result;// 若存在就的存储结构则删除可选if (db.objectStoreNames.contains(productions)) {db.deleteObjectStore(productions);}// 创建对象存储keyPath 表示应该用作键存储对象的属性名db.createObjectStore(productions, {keyPath: id});
};事务 —— db.transaction()
IndexedDB 是基于事务的
创建对象存储之后剩下的所有操作都是通过事务完成的即若要 读写数据都要通过事务 把所有修改操作进行组织.
创建事务
通过 let transaction db.transaction() 方法来创建事务
db.transaction() — 不指定参数 则对数据库中所有 对象存储 有 只读 权限db.transaction(productions) — 只加载特定对象存储的事务只读 权限db.transaction([productions,xxx], readwrite) —— 加载多个对象存储的事务且权限为 读写
transaction.onerror (event) {// 整个事务被取消
};
transaction.oncomplete (event) {// 整个事务成功完成
};获取指定对象存储 —— transaction.objectStore()
通过 let store transaction.objectStore(productions) 获取 productions 的对象存储得到了对应的 对象存储 后就可以使用以下方法
store.get() — 获取数据store.getAll() — 获取所有数据store.add() — 添加数据store.put() — 更新数据store.delete() — 删除数据store.clear() — 清除数据…
写入对象
通过对象存储的引用 store 使用 store.add() 和 store.put() 往对象存储中写入数据它们都只接收一个要存储的对象作为参数前提是这个对象必须包含存储对象中的 keyPath 属性对应的属性字段.
对象存储中已存在 同名的键 时:
store.add() 导致错误store.put() 重写该对象
// productions 是一个产品数组
let request, requests [];
for (let product of productions) {request store.add(product);request.onerror () {// 处理错误};request.onsuccess () {// 处理成功};requests.push(request);
}查询数据
键查询 —— store.get()
键指的就是 onupgradeneeded 中指定的 keyPath 属性所对应的值比如在上面我们指定了 { keyPath: id }那么在使用键查询时就必须要使用已存储数据对应属性的对应值. 假设需要获取如上图中的数据
let storeName productions
// 先创建事务通过事务获取指定的存储对象
let store db.transaction(storeName, readwrite).objectStore(storeName)
// 通过存储对象的 get 方法以及对应的 keyPath 键的 id 属性值获取数据
let request store.get(1643527674720);
request.onsuccess (event) {console.log(event.target.result);
}
request.onerror (event) {console.log(query_key error with code${event.target.errorCode});
}索引查询 —— store.index(key).get(value)
对某些数据集可能需要为对象存储指定多个键以便于后续查询数据时可以通过不同的键去获取需要创建存储对象时使用 store.createIndex() 去创建索引即 onupgradeneeded 事件处理程序中如下创建了一个名为 price 的索引后续查询数据时就可以使用这个所以名和对应的值进行查找
创建索引
request.onupgradeneeded (event) {db event.target.resultdb.createObjectStore(productions, {keyPath: id}).createIndex(price, price, {unique: false});
};使用索引 let storeName productionslet store db.transaction(storeName, readwrite).objectStore(storeName)let request store.index(price).get(72.57);request.onsuccess (event) {console.log(event.target.result);}request.onerror (event) {console.log(query_index error with code${event.target.errorCode});}游标查询 —— store.openCursor() cursor.continue()
从上面可以知道使用事务通过一个已知键或者索引都可以取得一条记录但如果想取得多条数据那就需要在事务中创建一个游标.
let cursorRequest store.openCursor();
cursorRequest.onsuccess (event) {let cursor event.target.result;// 当游标 cursor 值不存在时代表游标查找结束或出现异常所以需要提前判断if (!cursor) return;console.log(cursor.value);// 在本次游标指向中通过显示调用 continue 方法就可以将游标指向下一个数据cursor.continue();
}
cursorRequest.onerror (event) {console.log(query_cursor error with code${event.target.errorCode});
}范围查找 —— index索引 cursor游标 IDBKeyRange键范围
IDBKeyRange键范围
IDBKeyRange.only(1643607832742) 得到对应键值的记录IDBKeyRange.lowerBound(1643607832742, false) 得到对应键值的下限开始位置第二个参数: false —— 从 1643607832742 记录开始直到最后true —— 从 1643607832742 的下一条记录开始直到最后 IDBKeyRange.upperBound(1643607832742, false) 得到对应键值的上限结束位置第二个参数: false —— 从头开始到 1643607832742 记录为止true —— 从头开始到 1643607832742 的前一条记录为止 IDBKeyRange.bound() —— 同时指定上下限接收四个参数下限键、上限键、 可选布尔值 表示是否 跳过下限 、可选布尔值 是否 跳过上限
使用这样的查找方式更加理想因为这样的方式可以实现根据指定索引在指定范围内开始游标查询实现比较合理的范围查找. let request store.index(price).openCursor(IDBKeyRange.only(1643607832742));
request.onsuccess (event) {let cursor event.target.result;if (!cursor) return;console.log(cursor.value);cursor.continue();
}
request.onerror (event) {console.log(query_idnex_cursor error with code${event.target.errorCode});
}实现分页查询
模拟数据
要实现查询的前提是得先有数据这里就通过 setTimeout 模拟异步请求获取数据
const getData () {setTimeout(() {const list []const now Date.now()for (let index 0; index 100; index) {let price Math.random() * 100price price 10 ? price 10 : pricelist.push({id: now index,name: 产品_${index 1},price: price.toFixed(2)})}data.value list})
}然后通过循环调用 add() 方法将数写入到数据库中
const inser (data []) {let objectStore db.transaction(storeName, readwrite).objectStore(storeName)data.forEach(item objectStore.add({ ...item }))console.log(数据插入成功)
} 分页效果
实现效果如下 主要代码
useIndexDB.js
let db null
let storeName test_db
let lastRecords []
let currSize 0
let indexArr [name, price]const getStoreByTransaction () db.transaction(storeName, readwrite).objectStore(storeName)const query (payload) {return new Promise((resovle, reject) {let records []let { name, value, type, size 10 } payload || {}let objectStore getStoreByTransaction()let requestif (type) {request type next? objectStore.openCursor(IDBKeyRange.lowerBound(lastRecords[lastRecords.length - 1].id, type)): objectStore.openCursor(IDBKeyRange.upperBound(lastRecords[0].id, true), type)} else {request name? objectStore.index(name).openCursor(IDBKeyRange.only(value), type): objectStore.openCursor()}lastRecords []request.onsuccess (event) {let cursor event.target.resultif (!cursor || currSize size) {currSize 0resovle(records)return}let lastItem cursor.valuelastRecords.push(lastItem)records.push(lastItem)currSizeif (!name) {cursor.continue()} else {currSize 0resovle(records)}}request.onerror (event) {reject(query_idnex_cursor error with code${event.target.errorCode})}})
}const inser (data []) {let objectStore db.transaction(storeName, readwrite).objectStore(storeName)data.forEach(item objectStore.add({ ...item }))console.log(数据插入成功)
}const open (payload) {payload payload || { name: test, version: 1, storeName: productions }return new Promise((resovle, reject) {let request indexedDB.open(payload.name, payload.version)storeName payload.storeNamerequest.onsuccess (event) {db event.target.resultresovle({query,inser,getStoreByTransaction,db})console.log(Database connection successfully established)}request.onerror (event) {reject(Failed to open: ${event.target.errorCode})}request.onupgradeneeded (event) {db event.target.resultif (db.objectStoreNames.contains(productions)) {db.deleteObjectStore(productions)}let objectStore db.createObjectStore(productions, {keyPath: id})indexArr.forEach((name) {objectStore.createIndex(name, name, {unique: false})})}})
}export default openApp.vue
script setup langts
import { reactive, ref, onMounted, computed } from vue
import openDB from ./useIndexDB.js;const data ref([])
const queryResult ref([])
const formItem reactive({ price: , name: })
let dbObj nullonMounted(() {openDB().then(({ query, inser }) {dbObj { query, inser }})
})const getData () {setTimeout(() {const list []const now Date.now()for (let index 0; index 100; index) {let price Math.random() * 100price price 10 ? price 10 : pricelist.push({id: now index,name: 产品_${index 1},price: price.toFixed(2)})}data.value listconsole.log(数据获取成功, data.value);})
}const insertData () {dbObj.inser(data.value)
}const payload computed(() {let obj { value: formItem.name }if (formItem.name) {obj.name nameobj.value formItem.name}if (formItem.price) {obj.name priceobj.value formItem.price}return obj
})const loadPage (type) {dbObj.query({ type }).then((result) {console.log(result)queryResult.value result.sort((a,b) a.id - b.id)})
}const queryData () {dbObj.query({ ...payload.value }).then((result) {console.log(result)queryResult.value result.sort()})
}/scripttemplatediv classbtn-boxbutton clickgetData获取数据/buttonbutton clickinsertData插入数据/button/divdiv classboxlabel forname名称input idname v-modelformItem.name typetext //labellabel forprice价格input idprice v-modelformItem.price typetext //labelbutton classbtn clickqueryData查询/button/divul classlist v-showqueryResult.lengthli v-foritem in queryResult :keyitem.id{{item.name}} —— {{ item.price}}/lidivbutton clickloadPage(prev)上一页/buttonbutton clickloadPage(next)下一页/button/div/ul
/templatestyle
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;transition: all 0.5s ease;
}
.box label {margin: 0 10px;
}
button {margin: 10px;
}
.list{width: 400px;margin: 10px auto;
}
/style