fix: 多个页面共享同一 indexedDB 库导致异常(#111)

This commit is contained in:
pipipi-pikachu 2022-05-27 10:26:19 +08:00
parent f19ca86283
commit 7b07629a58
5 changed files with 62 additions and 19 deletions

View File

@ -8,6 +8,7 @@
import { defineComponent, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useScreenStore, useMainStore, useSnapshotStore } from '@/store'
import { LOCALSTORAGE_KEY_DISCARDED_DB } from '@/configs/storage'
import { isPC } from './utils/common'
import Editor from './views/Editor/index.vue'
@ -24,6 +25,7 @@ export default defineComponent({
setup() {
const mainStore = useMainStore()
const snapshotStore = useSnapshotStore()
const { databaseId } = storeToRefs(mainStore)
const { screening } = storeToRefs(useScreenStore())
if (process.env.NODE_ENV === 'production') {
@ -35,6 +37,17 @@ export default defineComponent({
mainStore.setAvailableFonts()
})
// localStorage indexedDB ID
window.addEventListener('unload', () => {
const discardedDB = localStorage.getItem(LOCALSTORAGE_KEY_DISCARDED_DB)
const discardedDBList: string[] = discardedDB ? JSON.parse(discardedDB) : []
discardedDBList.push(databaseId.value)
const newDiscardedDB = JSON.stringify(discardedDBList)
localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB)
})
return {
screening,
isPC: isPC(),

1
src/configs/storage.ts Normal file
View File

@ -0,0 +1 @@
export const LOCALSTORAGE_KEY_DISCARDED_DB = 'PPTIST_DISCARDED_DB'

View File

@ -1,3 +1,4 @@
import { customAlphabet } from 'nanoid'
import { defineStore } from 'pinia'
import { CreatingElement } from '@/types/edit'
import { ToolbarStates } from '@/types/toolbar'
@ -8,8 +9,6 @@ import { isSupportFont } from '@/utils/font'
import { useSlidesStore } from './slides'
export interface MainState {
activeElementIdList: string[];
handleElementId: string;
@ -31,8 +30,12 @@ export interface MainState {
selectedTableCells: string[];
selectedSlidesIndex: number[];
dialogForExport: DialogForExportTypes;
databaseId: string;
}
const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')
export const databaseId = nanoid(10)
export const useMainStore = defineStore('main', {
state: (): MainState => ({
activeElementIdList: [], // 被选中的元素ID集合包含 handleElementId
@ -55,6 +58,7 @@ export const useMainStore = defineStore('main', {
isScaling: false, // 正在进行元素缩放
selectedSlidesIndex: [], // 当前被选中的页面索引集合
dialogForExport: '', // 导出面板
databaseId, // 标识当前应用的indexedDB数据库ID
}),
getters: {

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { IndexableTypeArray } from 'dexie'
import { snapshotDB, Snapshot } from '@/utils/database'
import { db, deleteDiscardedDB, Snapshot } from '@/utils/database'
import { useSlidesStore } from './slides'
import { useMainStore } from './main'
@ -36,18 +36,13 @@ export const useSnapshotStore = defineStore('snapshot', {
async initSnapshotDatabase() {
const slidesStore = useSlidesStore()
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
const lastSnapshot = snapshots.slice(-1)[0]
if (lastSnapshot) {
snapshotDB.snapshots.clear()
}
await deleteDiscardedDB()
const newFirstSnapshot = {
index: slidesStore.slideIndex,
slides: slidesStore.slides,
}
await snapshotDB.snapshots.add(newFirstSnapshot)
await db.snapshots.add(newFirstSnapshot)
this.setSnapshotCursor(0)
this.setSnapshotLength(1)
},
@ -56,7 +51,7 @@ export const useSnapshotStore = defineStore('snapshot', {
const slidesStore = useSlidesStore()
// 获取当前indexeddb中全部快照的ID
const allKeys = await snapshotDB.snapshots.orderBy('id').keys()
const allKeys = await db.snapshots.orderBy('id').keys()
let needDeleteKeys: IndexableTypeArray = []
@ -72,7 +67,7 @@ export const useSnapshotStore = defineStore('snapshot', {
index: slidesStore.slideIndex,
slides: slidesStore.slides,
}
await snapshotDB.snapshots.add(snapshot)
await db.snapshots.add(snapshot)
// 计算当前快照长度,用于设置快照指针的位置(此时指针应该处在最后一位,即:快照长度 - 1
let snapshotLength = allKeys.length - needDeleteKeys.length + 1
@ -87,10 +82,10 @@ export const useSnapshotStore = defineStore('snapshot', {
// 快照数大于1时需要保证撤回操作后维持页面焦点不变也就是将倒数第二个快照对应的索引设置为当前页的索引
// https://github.com/pipipi-pikachu/PPTist/issues/27
if (snapshotLength >= 2) {
snapshotDB.snapshots.update(allKeys[snapshotLength - 2] as number, { index: slidesStore.slideIndex })
db.snapshots.update(allKeys[snapshotLength - 2] as number, { index: slidesStore.slideIndex })
}
await snapshotDB.snapshots.bulkDelete(needDeleteKeys)
await db.snapshots.bulkDelete(needDeleteKeys)
this.setSnapshotCursor(snapshotLength - 1)
this.setSnapshotLength(snapshotLength)
@ -103,7 +98,7 @@ export const useSnapshotStore = defineStore('snapshot', {
const mainStore = useMainStore()
const snapshotCursor = this.snapshotCursor - 1
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray()
const snapshot = snapshots[snapshotCursor]
const { index, slides } = snapshot
@ -122,7 +117,7 @@ export const useSnapshotStore = defineStore('snapshot', {
const mainStore = useMainStore()
const snapshotCursor = this.snapshotCursor + 1
const snapshots: Snapshot[] = await snapshotDB.snapshots.orderBy('id').toArray()
const snapshots: Snapshot[] = await db.snapshots.orderBy('id').toArray()
const snapshot = snapshots[snapshotCursor]
const { index, slides } = snapshot

View File

@ -1,16 +1,46 @@
import Dexie from 'dexie'
import { databaseId } from '@/store/main'
import { Slide } from '@/types/slides'
import { LOCALSTORAGE_KEY_DISCARDED_DB } from '@/configs/storage'
export interface Snapshot {
index: number;
slides: Slide[];
}
class SnapshotDatabase extends Dexie {
const databaseNamePrefix = 'PPTist'
// 删除失效/过期的数据库
// 应用关闭时关闭或刷新浏览器会将其数据库ID记录在 localStorage 中表示该ID指向的数据库已失效
// 当应用初始化时,检查当前所有数据库,将被记录失效的数据库删除
// 另外距离初始化时间超过12小时的数据库也将被删除这是为了防止出现因以外未被正确删除的库
export const deleteDiscardedDB = async () => {
const now = new Date().getTime()
const localStorageDiscardedDB = localStorage.getItem(LOCALSTORAGE_KEY_DISCARDED_DB)
const localStorageDiscardedDBList: string[] = localStorageDiscardedDB ? JSON.parse(localStorageDiscardedDB) : []
const databaseNames = await Dexie.getDatabaseNames()
const discardedDBNames = databaseNames.filter(name => {
if (name.indexOf(databaseNamePrefix) === -1) return false
const [prefix, id, time] = name.split('_')
if (prefix !== databaseNamePrefix || !id || !time) return true
if (localStorageDiscardedDBList.includes(id)) return true
if (now - (+time) >= 1000 * 60 * 60 * 12) return true
return false
})
for (const name of discardedDBNames) Dexie.delete(name)
localStorage.removeItem(LOCALSTORAGE_KEY_DISCARDED_DB)
}
class PPTistDB extends Dexie {
public snapshots: Dexie.Table<Snapshot, number>
public constructor() {
super('SnapshotDatabase')
super(`${databaseNamePrefix}_${databaseId}_${new Date().getTime()}`)
this.version(1).stores({
snapshots: '++id'
})
@ -18,4 +48,4 @@ class SnapshotDatabase extends Dexie {
}
}
export const snapshotDB = new SnapshotDatabase()
export const db = new PPTistDB()