From 08146c4497ecccd46fcb6ee68220a7e96e12e93b Mon Sep 17 00:00:00 2001 From: starknt <1431880400@qq.com> Date: Mon, 8 Jan 2024 10:41:18 +0800 Subject: [PATCH] refactor: share search history --- src/components/SearchBar/SearchBar.vue | 16 ++- .../SearchBar/searchHistoryProvider.ts | 98 +++++++++++++++---- src/utils/lazyLoad.ts | 18 ++++ 3 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/components/SearchBar/SearchBar.vue b/src/components/SearchBar/SearchBar.vue index b0070a70..e0623801 100644 --- a/src/components/SearchBar/SearchBar.vue +++ b/src/components/SearchBar/SearchBar.vue @@ -24,7 +24,7 @@ const suggestionItemRef = ref([]) watch(isFocus, async (focus) => { // 延后加载搜索历史 if (focus) - searchHistory.value = getSearchHistory() + searchHistory.value = await getSearchHistory() }) function handleInput() { @@ -46,21 +46,19 @@ function handleInput() { } } -function navigateToSearchResultPage(keyword: string) { +async function navigateToSearchResultPage(keyword: string) { if (keyword) { window.open(`//search.bilibili.com/all?keyword=${keyword}`, '_blank') const searchItem = { value: keyword, timestamp: Number(new Date()), } - addSearchHistory(searchItem) - searchHistory.value = getSearchHistory() + searchHistory.value = await addSearchHistory(searchItem) } } -function handleDelete(value: string) { - removeSearchHistory(value) - searchHistory.value = getSearchHistory() +async function handleDelete(value: string) { + searchHistory.value = await removeSearchHistory(value) } function handleKeyUp() { @@ -129,8 +127,8 @@ function handleKeyDown() { }) } -function handleClearSearchHistory() { - clearAllSearchHistory() +async function handleClearSearchHistory() { + await clearAllSearchHistory() searchHistory.value = [] } diff --git a/src/components/SearchBar/searchHistoryProvider.ts b/src/components/SearchBar/searchHistoryProvider.ts index a5380557..ac399531 100644 --- a/src/components/SearchBar/searchHistoryProvider.ts +++ b/src/components/SearchBar/searchHistoryProvider.ts @@ -1,4 +1,5 @@ -const SEARCH_HISTORY_KEY = 'bew_search_history' +import { LazyValue } from '~/utils/lazyLoad' + const SEARCH_HISTORY_LIMIT = 20 export interface HistoryItem { @@ -28,17 +29,77 @@ function historySort(historyItems: HistoryItem[]) { return historyItems } -export function getSearchHistory(): HistoryItem[] { - const history = localStorage.getItem(SEARCH_HISTORY_KEY) - if (!history) { - localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify([])) - return [] - } - return historySort(JSON.parse(history)) +export interface BilibiliStorageEvent { + type: 'COLS_RES' + id?: string + key: string + value: string } -export function addSearchHistory(historyItem: HistoryItem) { - let history = getSearchHistory() +class BilibiliStorageProvider { + static BILIBILI_HISTORY_KEY = 'search_history:search_history' + + private readonly iframe = new LazyValue(() => Array.from(document.getElementsByTagName('iframe')).find(i => i.src.includes('https://s1.hdslb.com/bfs/seed/jinkela/short/cols/iframe.html'))!) + + private async operate(type: 'COLS_GET'): Promise + private async operate(type: 'COLS_SET', value: string): Promise + private async operate(type: 'COLS_CLR'): Promise + private async operate(type: 'COLS_GET' | 'COLS_CLR' | 'COLS_SET', value?: string) { + const iframe = this.iframe.value + + switch (type) { + case 'COLS_GET': + return new Promise((resolve) => { + iframe.contentWindow!.postMessage({ type: 'COLS_GET', key: BilibiliStorageProvider.BILIBILI_HISTORY_KEY }, iframe!.src) + window.addEventListener('message', (e: MessageEvent) => { + if (e.origin === 'https://s1.hdslb.com' && e.data && e.data?.type === 'COLS_RES' && e.data?.key === BilibiliStorageProvider.BILIBILI_HISTORY_KEY) + resolve(e.data) + }, { once: true }) + }) + case 'COLS_CLR': + return iframe.contentWindow!.postMessage({ type: 'COLS_CLR', key: 'search_history' }, iframe.src) + case 'COLS_SET': + return iframe.contentWindow!.postMessage({ type: 'COLS_SET', key: BilibiliStorageProvider.BILIBILI_HISTORY_KEY, value }, iframe.src) + } + } + + getSearchHistory() { + return this.operate('COLS_GET') + } + + clearSearchHistory() { + return this.operate('COLS_CLR') + } + + addSearchHistory(value: string) { + return this.operate('COLS_SET', value) + } + + removeSearchHistory(value: string) { + return this.operate('COLS_SET', value) + } +} + +const provider = new BilibiliStorageProvider() + +export async function getSearchHistory(): Promise { + const e = await provider.getSearchHistory() + + if (!e) + return [] + + try { + const history = JSON.parse(e.value) + return historySort(history) + } + catch (error) { + console.error(error) + return [] + } +} + +export async function addSearchHistory(historyItem: HistoryItem) { + let history = await getSearchHistory() let hasSameValue = false history.forEach((item) => { @@ -54,18 +115,21 @@ export function addSearchHistory(historyItem: HistoryItem) { history = history.filter((item, index) => { if (index < SEARCH_HISTORY_LIMIT) return item - else return false + else + return false }) - localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(history)) + provider.addSearchHistory(JSON.stringify(history)) + return history } -export function removeSearchHistory(value: string) { - let history = getSearchHistory() +export async function removeSearchHistory(value: string) { + let history = await getSearchHistory() history = history.filter(item => item.value !== value) - localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(history)) + provider.removeSearchHistory(JSON.stringify(history)) + return history } -export function clearAllSearchHistory() { - localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify([])) +export async function clearAllSearchHistory() { + return provider.clearSearchHistory() } diff --git a/src/utils/lazyLoad.ts b/src/utils/lazyLoad.ts index 6180711a..4756d469 100644 --- a/src/utils/lazyLoad.ts +++ b/src/utils/lazyLoad.ts @@ -74,3 +74,21 @@ declare function cancelIdleCallback(handle: number): void; } } })() + +// TODO: handle error +export class LazyValue { + private _value: T | undefined + private _didRun = false + + constructor( + private executor: () => T, + ) {} + + get value(): T { + if (!this._didRun) { + this._value = this.executor() + this._didRun = true + } + return this._value! + } +}