跨浏览器存储IndexedDB增删改查查

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索

浏览器存储对比

特性 cookie sessionStorage localStorage indexedDB
数据存储周期 一般由服务器生成,可以设置过期时间; 前端采用和js-cookie等组件也可以生成 页面关闭就清理刷新依然存在 除非被清理,否则一直存在; 浏览器关闭还会保存在本地 除非被清理,否则一直存在
是否支持跨页面
是否支持跨浏览器
数据存储大小 4K SessionStorage默认能够存储5-10MB的数据根据当前浏览器的空闲空间来判断能够分配多少存储空间 Safari: 5MB ;Chrome: 10MB ;Internet Explorer: 10MB;Mozilla Firefox: 10MB ;Opera: 10MB 不限制大小
与服务端通信 每次都会携带在请求的header 中,对于请求性能有影响; 同时由于请求中都带有,所以也容易出现安全问题 不参与 不参与 不参与
特点 字符串键值对在本地存储数据 字符串键值对在本地存储数据 字符串键值对在本地存储数据 IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作),用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索

通过以上对比,我们如果需要使用到大数据存储且跨越浏览器的时候可以使用indexedDB进行处理,我们先看下浏览器的支持情况

浏览器支持情况

使用场景

IndexDB 是一种浏览器内置的数据库,它可以在浏览器中存储大量的数据,而不需要依赖于服务器。

  • 离线应用

IndexDB 可以在浏览器中存储大量的数据,这使得它非常适合用于离线应用。 当用户离线时,应用程序可以从IndexDB 中读取数据, 而不需要依赖于服务器。这使得应用程序可以在没有网络连接的情况下继续运行,从而提高了用户体验。

  • 缓存数据

IndexDB 可以用于缓存数据,这使得应用程序可以更快地加载数据。

当应用程序需要加载数据时,它可以首先从IndexDB中读取数据,

而不需要从服务器中获取数据。这可以大大减少网络请求的数量,

从而提高应用程序的性能。

  • 数据存储

IndexDB 可以用于存储大量的数据,这使得它非常适合用于需要存

储大量数据的应用程序。例如,一个在线笔记应用程序可以使用

IndexDB 来存储用户的笔记,而不需要依赖于服务器。

  • 数据同步

IndexDB 可以用于数据同步,这使得应用程序可以在多个设备之间

同步数据。当用户在一个设备上更新数据时,应用程序可以将数据

存储在 IndexDB 中,并将数据同步到其他设备上。这可以使用户在

不同设备上访问相同的数据,从而提高用户体验。

浏览器查看位置

  • 左侧为Chrome ,右侧为Safari

数据库操作

新增打开数据库

js 复制代码
/**
 * version:如果需要新增表,需要加版本号
 * 打开数据库
 */
export function openDB(dbName, storeName, version = 1) {
    return new Promise((resolve, reject) => {
        let indexedDB = window.indexedDB
        let db
        const request = indexedDB.open(dbName, version)
        request.onsuccess = function (event) {
            db = event.target.result // 数据库对象
            resolve(db)
        }

        request.onerror = function (event) {
            reject(event)
        }

        request.onupgradeneeded = function (event) {
            // 数据库创建或升级的时候会触发
            console.log('onupgradeneeded')
            db = event.target.result // 数据库对象
            let objectStore
            if (!db.objectStoreNames.contains(storeName)) {
                objectStore = db.createObjectStore(storeName, { keyPath: 'id' }) // 创建表
                // objectStore.createIndex('name', 'name', { unique: true }) // 创建索引 可以让你搜索任意字段
            }
        }
    })
}

删除数据库

js 复制代码
/**
 * 删除数据库
 */
export function deleteDBAll(dbName) {
    console.log(dbName)
    let deleteRequest = window.indexedDB.deleteDatabase(dbName)
    return new Promise((resolve, reject) => {
        deleteRequest.onerror = function (event) {
            console.log('删除失败')
        }
        deleteRequest.onsuccess = function (event) {
            console.log('删除成功')
        }
    })
}

关闭数据库

js 复制代码
/**
 * 关闭数据库
 */
export function closeDB(db) {
    db.close()
    console.log('数据库已关闭')
}

数据处理

新增数据

js 复制代码
/**
 * 新增数据
 */
export function addData(db, storeName, data) {
    return new Promise((resolve, reject) => {
        let request = db.transaction([storeName], 'readwrite') // 事务对象 指定表格名称和操作模式("只读"或"读写")
            .objectStore(storeName) // 仓库对象
            .add(data)

        request.onsuccess = function (event) {
            resolve(event)
        }

        request.onerror = function (event) {
            throw new Error(event.target.error)
            reject(event)
        }
    })
}

通过主键读取数据

js 复制代码
/**
 * 通过主键读取数据
 */
export function getDataByKey(db, storeName, key) {
    return new Promise((resolve, reject) => {
        let transaction = db.transaction([storeName]) // 事务
        let objectStore = transaction.objectStore(storeName) // 仓库对象
        let request = objectStore.get(key)

        request.onerror = function (event) {
            reject(event)
        }

        request.onsuccess = function (event) {
            resolve(request.result)
        }
    })
}

更新数据

js 复制代码
export function updateDB(db, storeName, data) {
    let request = db.transaction([storeName], 'readwrite') // 事务对象
        .objectStore(storeName) // 仓库对象
        .put(data)

    return new Promise((resolve, reject) => {
        request.onsuccess = function (ev) {
            resolve(ev)
        }

        request.onerror = function (ev) {
            resolve(ev)
        }
    })
}

删除数据

js 复制代码
export function deleteDB(db, storeName, id) {
    let request = db.transaction([storeName], 'readwrite').objectStore(storeName).delete(id)

    return new Promise((resolve, reject) => {
        request.onsuccess = function (ev) {
            resolve(ev)
        }

        request.onerror = function (ev) {
            resolve(ev)
        }
    })
}

获取全部数据

js 复制代码
/**
 * 获取所有数据
 */
export function getDataAll(db, storeName) {
    let store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    var request = store.getAll();
    return new Promise((resolve, reject) => {
        request.onerror = function (e) {
            reject(e)
        }
        request.onsuccess = function (e) {
            resolve(request.result)
        }
    })
}

第三方组件库

# ts-indexdb

完整代码

indexDBTest源码

IndexDB.js

js 复制代码
/**
 * 封装的方法以及用法
 * 打开数据库
 */
export function openDB(dbName, storeName, version = 1) {
    return new Promise((resolve, reject) => {
        let indexedDB = window.indexedDB
        let db
        const request = indexedDB.open(dbName, version)
        request.onsuccess = function (event) {
            db = event.target.result // 数据库对象
            resolve(db)
        }

        request.onerror = function (event) {
            reject(event)
        }

        request.onupgradeneeded = function (event) {
            // 数据库创建或升级的时候会触发
            console.log('onupgradeneeded')
            db = event.target.result // 数据库对象
            let objectStore

            if (!db.objectStoreNames.contains(storeName)) {
                objectStore = db.createObjectStore(storeName, { keyPath: 'id' }) // 创建表
                // objectStore.createIndex('name', 'name', { unique: true }) // 创建索引 可以让你搜索任意字段
            }
        }
    })
}

/**
 * 新增数据
 */
export function addData(db, storeName, data) {
    return new Promise((resolve, reject) => {
        let request = db.transaction([storeName], 'readwrite') // 事务对象 指定表格名称和操作模式("只读"或"读写")
            .objectStore(storeName) // 仓库对象
            .add(data)

        request.onsuccess = function (event) {
            resolve(event)
        }

        request.onerror = function (event) {
            throw new Error(event.target.error)
            reject(event)
        }
    })
}

/**
 * 通过主键读取数据
 */
export function getDataByKey(db, storeName, key) {
    return new Promise((resolve, reject) => {
        let transaction = db.transaction([storeName]) // 事务
        let objectStore = transaction.objectStore(storeName) // 仓库对象
        let request = objectStore.get(key)

        request.onerror = function (event) {
            reject(event)
        }

        request.onsuccess = function (event) {
            resolve(request.result)
        }
    })
}

/**
 * 通过游标读取数据
 */
export function cursorGetData(db, storeName) {
    let list = []
    let store = db.transaction(storeName, 'readwrite') // 事务
        .objectStore(storeName) // 仓库对象
    let request = store.openCursor() // 指针对象
    return new Promise((resolve, reject) => {
        request.onsuccess = function (e) {
            let cursor = e.target.result
            if (cursor) {
                // 必须要检查
                list.push(cursor.value)
                cursor.continue() // 遍历了存储对象中的所有内容
            } else {
                resolve(list)
            }
        }
        request.onerror = function (e) {
            reject(e)
        }
    })
}

/**
 * 通过索引读取数据
 */
export function getDataByIndex(db, storeName, indexName, indexValue) {
    let store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    let request = store.index(indexName).get(indexValue)
    return new Promise((resolve, reject) => {
        request.onerror = function (e) {
            reject(e)
        }
        request.onsuccess = function (e) {
            resolve(e.target.result)
        }
    })
}
/**
 * 获取所有数据
 */
export function getDataAll(db, storeName) {
    let store = db.transaction(storeName, 'readwrite').objectStore(storeName)
    var request = store.getAll();
    return new Promise((resolve, reject) => {
        request.onerror = function (e) {
            reject(e)
        }
        request.onsuccess = function (e) {
            resolve(request.result)
        }
    })
}

/**
 * 通过索引和游标查询记录
 */
export function cursorGetDataByIndex(db, storeName, indexName, indexValue) {
    let list = []
    let store = db.transaction(storeName, 'readwrite').objectStore(storeName) // 仓库对象
    let request = store.index(indexName) // 索引对象
        .openCursor(IDBKeyRange.only(indexValue)) // 指针对象
    return new Promise((resolve, reject) => {
        request.onsuccess = function (e) {
            let cursor = e.target.result
            if (cursor) {
                list.push(cursor.value)
                cursor.continue() // 遍历了存储对象中的所有内容
            } else {
                resolve(list)
            }
        }
        request.onerror = function (ev) {
            reject(ev)
        }
    })
}

/**
 * 更新数据
 */
export function updateDB(db, storeName, data) {
    let request = db.transaction([storeName], 'readwrite') // 事务对象
        .objectStore(storeName) // 仓库对象
        .put(data)

    return new Promise((resolve, reject) => {
        request.onsuccess = function (ev) {
            resolve(ev)
        }

        request.onerror = function (ev) {
            resolve(ev)
        }
    })
}

/**
 * 删除数据
 */
export function deleteDB(db, storeName, id) {
    let request = db.transaction([storeName], 'readwrite').objectStore(storeName).delete(id)

    return new Promise((resolve, reject) => {
        request.onsuccess = function (ev) {
            resolve(ev)
        }

        request.onerror = function (ev) {
            resolve(ev)
        }
    })
}

/**
 * 删除数据库
 */
export function deleteDBAll(dbName) {
    console.log(dbName)
    let deleteRequest = window.indexedDB.deleteDatabase(dbName)
    return new Promise((resolve, reject) => {
        deleteRequest.onerror = function (event) {
            console.log('删除失败')
        }
        deleteRequest.onsuccess = function (event) {
            console.log('删除成功')
        }
    })
}

/**
 * 关闭数据库
 */
export function closeDB(db) {
    db.close()
    console.log('数据库已关闭')
}

export default {
    openDB,
    addData,
    getDataByKey,
    cursorGetData,
    getDataByIndex,
    cursorGetDataByIndex,
    updateDB,
    deleteDB,
    deleteDBAll,
    closeDB,
    getDataAll
}

app.tsx

tsx 复制代码
import './app.css'
import IndexDB from './IndexDB.js'
import { Card, Button, Table, Row, Col, Space, Modal } from 'antd';
import { useState, useEffect } from 'react';
import ModalForm from './ModalForm';

export function App() {
  const [dataSource, setDataSource] = useState([])
  const dbName = 'myDB', storeName = 'db_1'

  async function createDB() {
    await IndexDB.openDB(dbName, storeName, 1)
  }

  async function getAll() {
    const db = await IndexDB.openDB(dbName, storeName, 1)
    var data = await IndexDB.getDataAll(db, storeName)
    setDataSource(data)
  }

  async function addTableInfo(valueNow) {
    const db = await IndexDB.openDB(dbName, storeName, 1)
    await IndexDB.addData(db, storeName, valueNow)
    setTimeout(() => {
      getAll()
    }, 1000);
  }
  async function updateTableInfo(valueNow) {
    const db = await IndexDB.openDB(dbName, storeName, 1)
    await IndexDB.updateDB(db, storeName, valueNow)
    setTimeout(() => {
      getAll()
    }, 1000);
  }

  async function getItemByKey(key) {
    const db = await IndexDB.openDB(dbName, storeName, 1)
    var data = await IndexDB.getDataByKey(db, storeName, key)
    Modal.confirm({
      title: data.name,
      content: JSON.stringify(data)
    })
  }

  async function deleteKey(key) {
    const db = await IndexDB.openDB(dbName, storeName, 1)
    await IndexDB.deleteDB(db, storeName, key)
    setTimeout(() => {
      getAll()
    }, 1000);
  }

  useEffect(() => {
    getAll()
  }, [])
  const columns = [
    {
      title: 'id',
      dataIndex: 'id',
    },
    {
      title: '姓名',
      dataIndex: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
    },
    {
      title: '操作',
      render: (text, record) => {
        return <Space>
          <a onClick={() => deleteKey(record.id)}>删除</a>
          <ModalForm dataInfo={record} onOK={updateTableInfo} btnText={<a>修改</a>} />
          <a onClick={() => getItemByKey(record.id)}>获取其他数据</a>
        </Space>
      }
    }
  ];

  return (
    <Space direction='vertical' size='large'>
      <Row >
        <Space>
          <Button onClick={createDB} type="primary">创建数据库</Button>
          <Button onClick={async () => await IndexDB.deleteDBAll(dbName)} danger>删除数据库</Button>
        </Space>
      </Row>
      <Row style={{ width: 1000 }}>
        <Col span={24}>
          <Card title='数据列表' extra={<ModalForm onOK={addTableInfo} />} >
            <Table
              dataSource={dataSource} columns={columns} />
          </Card>
        </Col>
      </Row>
    </Space>
  )
}

ModalForm.jsx

jsx 复制代码
import { Form, Input, Modal } from 'antd';
import { useState, useEffect } from 'react';
import { Button } from 'antd';


function ModalForm(props) {
    const [form] = Form.useForm()
    const [open, setOpen] = useState(false)
    useEffect(() => {
        if (open && props.dataInfo) {
            form.setFieldsValue(props.dataInfo)
        }
    }, [open])
    return (
        <div>
            <div onClick={() => setOpen(true)}>{props.btnText || <Button type='primary'>新增数据</Button>}</div>
            <Modal
                title="数据操作"
                open={open}
                destroyOnClose={true}
                onOk={async () => {
                    const values = form.getFieldsValue()
                    await props.onOK(values)
                    setOpen(false)
                }}
                onCancel={() => {
                    setOpen(false)
                }}
            >
                <Form form={form}>
                    <Form.Item label="主键" name='id'>
                        <Input placeholder="请输入" />
                    </Form.Item>
                    <Form.Item label="姓名" name='name'>
                        <Input placeholder="请输入" />
                    </Form.Item>
                    <Form.Item label="年龄" name='age'>
                        <Input placeholder="请输入" />
                    </Form.Item>
                    <Form.Item label="其他信息" name='desc'>
                        <Input placeholder="请输入" />
                    </Form.Item>
                </Form>
            </Modal>
        </div>
    )
}

export default ModalForm
相关推荐
梦境之冢17 分钟前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun20 分钟前
vue VueResource & axios
前端·javascript·vue.js
J总裁的小芒果36 分钟前
THREE.js 入门(六) 纹理、uv坐标
开发语言·javascript·uv
m0_5485147737 分钟前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
浮游本尊1 小时前
Nginx配置:如何在一个域名下运行两个网站
前端·javascript
新中地GIS开发老师1 小时前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
爱喝奶茶的企鹅1 小时前
Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践
react.js
Cachel wood2 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
放逐者-保持本心,方可放逐2 小时前
SSE 流式场景应用 及 方案总结
javascript·axios·fetch·eventsource
白云~️2 小时前
uniappX 移动端单行/多行文字隐藏显示省略号
开发语言·前端·javascript