在客户端,我们所接触到的绝大部分本地缓存方案主要有localStorage
以及sessionStorage
,其实Storage
除了这两大高频api,另外还有IndexDB
、cookies
、WebSQL
,Trust Token(信任令牌)
,cookies
相对来说在前端接触比另外几个多点,IndexDB
在平常业务中肯定有所耳闻,至于其他的貌似还真没用过🤣
本文是笔者关于IndexDB
的一个简单的实践示例,一起来学习下IndexDB,
因为有时候,可能真的很有用。
正文开始...
在阅读本文之前,本文主要从以下几点去探讨IndexDB
- 为什么会有
IndexDB
,本地localStorage
与sessionStorage
不够用吗 IndexDB
有何特征- 以一个示例加深对于
IndexDB
的理解 IndexDB
在什么情况下能为我们的业务解决什么样的问题
了解IndexDB
根据官方MDNIndex DB[1]文档查询解释
IndexDB
是浏览器提供的一种可持久化数据存储方案- 支持多种类型的键,可以支持存储任何类型的数据
- 支持键检索,查询,新增,删除操作
- 在客户端浏览器可以存储大数据量,适用于离线应用
- 所有接口都是基于事件 在与
lcoalStorage
或者seesionStorage
来说,IndexDB
存储数据量更大,更强大
IndexDB特征
你可以把IndexDB
当成一个本地的数据库,如果你要使用它。那么会有以下几个步骤
- 打开数据库,创建本地数据库并连接
IndexDB.open('lcoal-test')
- 创建对象库
db.createObjectStore('user')
- 基于事务操作本地数据库,实现增删查改
举个例子
本示例主要考虑最简单方式实现,也不依赖任何工程化工具,首先新建一个index.html
,在index.html
中引入vue2.7
,vue2.7
出来了,尝下鲜,主要支持组合式api方式了,基本api
使用上与组合式API
没有啥区别。
并且,这里我没有直接用原生IndexDB
,而是使用了官方文档推荐的一个库dexie.js[2],因为官方原生API
太难用了,而这个库是对原生IndexDB
的二次封装,使用起来更高效
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>初识index-db</title> <link rel="stylesheet" href="./css/index.css" /> </head> <body> <div id="app"> <h3>{{lesson}}</h3> <a href="javascript:void(0)" @click="handleAdd('add')">新增</a> <div class="content-box"> <div class="search-bar"> <input type="text" placeholder="请输入名称" v-model="searchName" /> <span @click="handleSearch">点击搜索</span> </div> <template v-for="(item) in initData"> <p> <span>{{item.name}}</span> <span>{{item.age}}</span> <span @click="handleAdd('edit',item)">编辑</span> <span @click="handleDel(item)">删除</span> </p> </template> </div> <div class="wrap-modal" v-if="showDiag"> <input placeholder="请输入name" v-model="formParams.name" /> <input placeholder="请输入age" v-model="formParams.age" /> <div> <span @click="handleSure">确认</span> </div> </div> </div> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.0/vue.min.js"></script> <script src="./js/dexie.min.js"></script> </body> </html>
然后我们引入业务js
... <script type="module"> // 引入hooks import { useApp, useIndexDB } from './hooks/index.js'; const { reactive, toRefs, createApp, onMounted } = Vue; const App = { setup() { const { searchName, lesson, initData, showDiag, view, formParams } = useApp(); const { add_indexDB, update_indexDB, search_indexDB, del_indexDB } = useIndexDB(); // todo 查询数据 const featchList = async (searchName = '') => { const colletion = await search_indexDB(searchName); initData.value = colletion; }; onMounted(() => { featchList(); }); // todo 编辑or添加 const handleAdd = (viewType, row) => { searchName.value = ''; view.value = viewType; showDiag.value = true; // 编辑 if (view.value === 'edit') { console.log(row); formParams.value = { ...row }; } else { // 添加 formParams.value.name = ''; formParams.value.age = ''; } }; const handleSure = () => { showDiag.value = false; view.value === 'edit' ? update_indexDB(formParams.value, featchList) : add_indexDB(formParams.value, featchList); }; const handleDel = (row) => { del_indexDB(row.id, featchList); }; // 搜索 const handleSearch = () => { featchList(searchName.value); }; return { searchName, lesson, showDiag, initData, formParams, handleAdd, handleSure, handleDel, handleSearch }; } }; // 绑定app const app = new Vue(App).$mount('#app'); </script>
我们看下这里面引入的useApp, useIndexDB
// hooks/index.js const { reactive, toRefs, ref } = Vue; export const useApp = () => { const useInfo = reactive({ lesson: '初识IndexDB,实现本地crud一把梭', initData: [], showDiag: false, view: 'add', searchName: '', formParams: { name: '', age: '' } }); return { ...toRefs(useInfo) } } // IndexDB hooks export const useIndexDB = () => { const db = new Dexie('local-test'); db.version(1).stores({ user: '++id, name, age' }); // 添加数据 const add_indexDB = (params, callback) => { db.user.add(params); callback(); } // 更新数据 const update_indexDB = (params, callback) => { db.user.put(params); callback() } // 查询 const search_indexDB = async (params) => { const colletion = params ? await db.user.where('name').equals(params).toArray() : await db.user.toArray(); return colletion; } // 删除 const del_indexDB = (id, callback) => { db.user.where('id').equals(id).delete(); callback(); } return { db, add_indexDB, update_indexDB, search_indexDB, del_indexDB } }
页面已经搭完,我们打开页面看下
- 新增
现在我们新增一条数据,在页面点击新增按钮,在applcation/Storage/IndexDB
中就会保存一条数据
当我们刷新时,数据页面仍然会保留上一次的数据
在我们新增操作,然后刷新的过程中主要发生了什么呢
其实IndexDB
主要做了以下几件事情
// hooks/index.js // 1 建立连接,创建db const db = new Dexie('local-test'); //2 创建了一个user的表名 db.version(1).stores({ user: '++id, name, age' }); // 3 向user中添加数据 // 添加数据 const add_indexDB = (params, callback) => { db.user.add(params); callback(); } //4 查询user表中的数据,并返回 const search_indexDB = async (params) => { const colletion = params ? await db.user.where('name').equals(params).toArray() : await db.user.toArray(); return colletion; }
在点击创建时,然后点击确认操作,就是在创建数据操作
... // 点击确认会调用这个方法 const handleSure = () => { // showDiag.value = false; view.value === 'edit' ? update_indexDB(formParams.value, featchList) : add_indexDB(formParams.value, featchList); };
并且注意,我们还传入了一个featchList
方法,这是在添加数据成功了,我们重新更新页面数据的一个回调
... // todo 查询数据 const featchList = async (searchName = '') => { const colletion = await search_indexDB(searchName); // 页面数据赋值 initData.value = colletion; }; ...
至此一个增加操作流程就已经结束
- 更新
当我们点击编辑时,我们尝试修改名称,然后点击确认,那么此时就调用更新数据操作
// hooks/index.js // 更新数据 const update_indexDB = (params, callback) => { db.user.put(params); callback() }
我们使用的是put
方法直接就可以更新数据了
更新前
当我点击编辑
更新后
我们可以刷新右侧的刷新按钮现实对应的数据
- 删除
... // 删除 const del_indexDB = (id, callback) => { db.user.where('id').equals(id).delete(); callback(); } ...
删除前
删除后
当我们删除后,又可以重新添加
但是我们发现,每次只能添加一次,如果重复添加,那么此时会添加不了
主要原因是store
中的key
重复了,无法重复添加,但是你把上一条删除了,你就可以重复添加了
而且你删除后,当你刷新页面,那条数据就真的没有,当你新增一条数据,只要你不删除,那么打开页面数据就会一直在页面中。
所以IndexDB
这个相当于在前端设计了一个小型数据库能力了
什么样业务适合用IndexDB
在上一个例子中,我们尝试用简单的一个例子去了解了IndexDB
,但是在具体实际业务中,我们也很少会使用IndexDB
去做这种杀鸡用牛刀的事,因为localStorage
与sessionStorage
也可以满足了,但如果是那种大数据量计算,如果涉及步骤操作那种,比如在这样的一个业务场景中,现在比较流行的低代码平台,拖拉拽的几个步骤就能生成一个页面,如果中途我只完成了一部分操作,页面不小心关掉了,此时如果你又让用户重新配置操作,那么体验就不会那么好,因此你可以尝试用IndexDB
去做你操作流程的本地数据持久化操作,因为IndexDB
可以存储足够大的数据量,你只需要保证你存的Schema
数据能正常渲染你的页面就行,或者你的暂存操作也可以不用服务端处理,暂存功能完全可以依赖客户端做,这样也会减少服务端的压力。
总结
- 基础的了解
IndexDB
,它是浏览器提供的一种可持久化缓存数据方案,相当于一个本地的数据库 - 写了一个简单的例子,支持
IndexDB
的增删查改功能 - 探讨了业务实际使用场景,一般用于存储大数据量,暂存操作等
- 本文示例code example[3]