feat: background image cache indexdb
This commit is contained in:
parent
64ad8215ac
commit
b5e222855e
16
.vscode/settings.json
vendored
16
.vscode/settings.json
vendored
|
@ -2,12 +2,14 @@
|
|||
"cSpell.words": [
|
||||
"ACGNGAME",
|
||||
"Akai",
|
||||
"Amayui",
|
||||
"arpa",
|
||||
"axios",
|
||||
"azkhx",
|
||||
"bangumi",
|
||||
"Bilibili",
|
||||
"Bishoujo",
|
||||
"Chuudoku",
|
||||
"Codepen",
|
||||
"cout",
|
||||
"dompurify",
|
||||
|
@ -16,11 +18,15 @@
|
|||
"Galgame",
|
||||
"Galworld",
|
||||
"gsap",
|
||||
"Hana",
|
||||
"Hikari",
|
||||
"Hitomi",
|
||||
"Hokenshitsu",
|
||||
"iconify",
|
||||
"INTLIFY",
|
||||
"Irotoridori",
|
||||
"Joshu",
|
||||
"Karenai",
|
||||
"kfmax",
|
||||
"Koori",
|
||||
"kungal",
|
||||
|
@ -28,10 +34,12 @@
|
|||
"kungalgamer",
|
||||
"ldquo",
|
||||
"Licence",
|
||||
"localforage",
|
||||
"loli",
|
||||
"majesticons",
|
||||
"Mangekyou",
|
||||
"Maniwa",
|
||||
"Meister",
|
||||
"mingcute",
|
||||
"Mirai",
|
||||
"mockjs",
|
||||
|
@ -40,22 +48,29 @@
|
|||
"Murasame",
|
||||
"Nanami",
|
||||
"nawa",
|
||||
"NEKOPARA",
|
||||
"non-moe",
|
||||
"nprogress",
|
||||
"okaidia",
|
||||
"Otome",
|
||||
"Owaru",
|
||||
"persistedstate",
|
||||
"Pinia",
|
||||
"prismjs",
|
||||
"rdquo",
|
||||
"Roka",
|
||||
"Sahou",
|
||||
"Sakura",
|
||||
"Sekai",
|
||||
"Senren",
|
||||
"Sensei",
|
||||
"Shabondama",
|
||||
"shinnku",
|
||||
"Shugaten",
|
||||
"signin",
|
||||
"sina",
|
||||
"SMEE",
|
||||
"Somnium",
|
||||
"tachi",
|
||||
"tada",
|
||||
"tdesign",
|
||||
|
@ -75,6 +90,7 @@
|
|||
"Vite",
|
||||
"VNDB",
|
||||
"vueup",
|
||||
"Wataridori",
|
||||
"weixin",
|
||||
"Wenders",
|
||||
"ymgal",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"animate.css": "^4.1.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"dompurify": "^3.0.6",
|
||||
"localforage": "^1.10.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.1.6",
|
||||
"pinia-plugin-persistedstate": "^3.2.0",
|
||||
|
|
|
@ -17,6 +17,9 @@ dependencies:
|
|||
dompurify:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
localforage:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
|
@ -1475,6 +1478,10 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/immediate@3.0.6:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
dev: false
|
||||
|
||||
/immutable@4.3.4:
|
||||
resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==}
|
||||
dev: true
|
||||
|
@ -1569,6 +1576,18 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/lie@3.1.1:
|
||||
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
dev: false
|
||||
|
||||
/localforage@1.10.0:
|
||||
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
|
||||
dependencies:
|
||||
lie: 3.1.1
|
||||
dev: false
|
||||
|
||||
/lodash.clonedeep@4.5.0:
|
||||
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
|
||||
dev: false
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
// 导入 vue 函数
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
// 导入设置面板 store
|
||||
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
|
||||
|
@ -9,46 +9,44 @@ import { storeToRefs } from 'pinia'
|
|||
// 全局消息组件(顶部)
|
||||
import Message from '@/components/alert/Message'
|
||||
|
||||
import backgroundImages from './background'
|
||||
|
||||
import { backgroundImages } from './background'
|
||||
import { getBackgroundURL } from '@/hooks/useBackgroundPicture'
|
||||
import { restoreBackground } from '@/hooks/useBackgroundPicture'
|
||||
|
||||
const imageArray = ref<string[]>([])
|
||||
// 使用设置面板的 store
|
||||
const settingsStore = useKUNGalgameSettingsStore()
|
||||
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
|
||||
storeToRefs(settingsStore)
|
||||
storeToRefs(useKUNGalgameSettingsStore())
|
||||
|
||||
// 获取背景图片略缩图
|
||||
const getBackground = async (imageNumber: number) => {
|
||||
return await getBackgroundURL(`bg${imageNumber}-m`)
|
||||
}
|
||||
|
||||
// 更改背景图片
|
||||
const handelChangeImage = (index: number) => {
|
||||
showKUNGalgameBackground.value = index.toString()
|
||||
showKUNGalgameBackground.value = `bg${index}`
|
||||
}
|
||||
|
||||
/* 测试图片:
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/1ee99996d0eb2646.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/87d94be5e004547a.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/2a639bd15113b570.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/b7c73a1643bdc55b.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ee67fdadd4104bbd.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/30aacd3045496498.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ab2da01971cc1629.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ed196495796482e4.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/a6dcdae0afe118f0.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/7aa57120cc6977a1.png
|
||||
*/
|
||||
|
||||
// 自定义背景
|
||||
const url = ref('')
|
||||
|
||||
const handleCustomBackground = () => {
|
||||
if (url.value) {
|
||||
showKUNGalgameCustomBackground.value = url.value
|
||||
showKUNGalgameBackground.value = '1007'
|
||||
showKUNGalgameBackground.value = 'bg1007'
|
||||
url.value = ''
|
||||
} else {
|
||||
Message('Please input valid image url', '请输入合法的图片链接', 'warn')
|
||||
}
|
||||
}
|
||||
// 恢复空白背景
|
||||
|
||||
onMounted(async () => {
|
||||
for (const background of backgroundImages) {
|
||||
const backgroundURL = await getBackground(background.index)
|
||||
imageArray.value.push(backgroundURL)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -61,7 +59,7 @@ const handleCustomBackground = () => {
|
|||
<ul class="kungalgame-restore-bg">
|
||||
<li v-for="kun in backgroundImages" :key="kun.index">
|
||||
<img
|
||||
:src="kun.image"
|
||||
:src="imageArray[kun.index - 1]"
|
||||
:alt="kun.alt"
|
||||
@click="handelChangeImage(kun.index)"
|
||||
/>
|
||||
|
|
|
@ -1,56 +1,57 @@
|
|||
/* 背景测试图片:
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/1ee99996d0eb2646.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/87d94be5e004547a.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/2a639bd15113b570.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/b7c73a1643bdc55b.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ee67fdadd4104bbd.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/30aacd3045496498.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ab2da01971cc1629.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/ed196495796482e4.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/a6dcdae0afe118f0.png
|
||||
https://s3.bmp.ovh/imgs/2023/05/30/7aa57120cc6977a1.png
|
||||
*/
|
||||
|
||||
interface background {
|
||||
index: number
|
||||
image: string
|
||||
alt: string
|
||||
}
|
||||
|
||||
// 定义背景图片列表
|
||||
const backgroundImages: background[] = [
|
||||
export const backgroundImages: background[] = [
|
||||
{
|
||||
index: 1,
|
||||
image: '/src/assets/images/bg/bg1-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Akai Hitomi ni Utsuru Sekai 紅い瞳に映るセカイ 红瞳映入的世界',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
image: '/src/assets/images/bg/bg2-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Shugaten! しゅがてん! 糖调',
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
image: '/src/assets/images/bg/bg3-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Amayui Castle Meister 天結いキャッスルマイスター 天结神缘',
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
image: '/src/assets/images/bg/bg4-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Pieces Wataridori no Somnium 渡り鳥のソムニウム 渡鸟的梦',
|
||||
},
|
||||
{
|
||||
index: 5,
|
||||
image: '/src/assets/images/bg/bg5-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Karenai Sekai to Owaru Hana 枯れない世界と終わる花 不败世界与终焉之花',
|
||||
},
|
||||
{
|
||||
index: 6,
|
||||
image: '/src/assets/images/bg/bg6-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'NEKOPARA ネコぱら 猫娘乐园',
|
||||
},
|
||||
{
|
||||
index: 7,
|
||||
image: '/src/assets/images/bg/bg7-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Sakura no Uta サクラノ詩 樱之诗',
|
||||
},
|
||||
{
|
||||
index: 8,
|
||||
image: '/src/assets/images/bg/bg8-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Hokenshitsu no Sensei to Shabondama Chuudoku no Joshu 保健室のセンセーとシャボン玉中毒の助手 保健室的老师与肥皂泡中毒的助手',
|
||||
},
|
||||
{
|
||||
index: 9,
|
||||
image: '/src/assets/images/bg/bg9-m.png',
|
||||
alt: 'azkhx',
|
||||
alt: 'Senren * Banka 千恋*万花 千恋*万花',
|
||||
},
|
||||
]
|
||||
|
||||
export default backgroundImages
|
||||
|
|
|
@ -1,28 +1,76 @@
|
|||
// 导入设置面板 store
|
||||
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
|
||||
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
|
||||
import { saveImage, getImage } from './useLocalforage'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed } from 'vue'
|
||||
|
||||
// 使用设置面板的 store
|
||||
const settingsStore = useKUNGalgameSettingsStore()
|
||||
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
|
||||
storeToRefs(settingsStore)
|
||||
|
||||
// 恢复空白背景
|
||||
export const restoreBackground = () => {
|
||||
showKUNGalgameBackground.value = '0'
|
||||
// 从后端获取背景图片数据
|
||||
const fetchGetBackground = async (imageName: string): Promise<Blob> => {
|
||||
const baseUrl = import.meta.env.VITE_API_BASE_URL
|
||||
const url = `/uploads/image/bg/${imageName}.webp`
|
||||
const fullUrl = `${baseUrl}${url}`
|
||||
const response = await fetch(fullUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${useKUNGalgameUserStore().getToken()}`,
|
||||
},
|
||||
})
|
||||
return await response.blob()
|
||||
}
|
||||
|
||||
export const currBackground = computed(() => {
|
||||
// 根据图片的序号获取图片链接
|
||||
const getBackgroundURL = async (imageName: string) => {
|
||||
// 本地保存的图片 blob 数据
|
||||
const backgroundImageBlobData = await getImage(imageName)
|
||||
|
||||
// 有数据则从本地创建 blob 链接
|
||||
if (backgroundImageBlobData) {
|
||||
return URL.createObjectURL(backgroundImageBlobData)
|
||||
} else {
|
||||
// 本地数据没有图片 blob 数据则从后端获取图片 blob 数据并存储在本地
|
||||
const imageBlob = await fetchGetBackground(`${imageName}`)
|
||||
console.log('调用 fetch get blob')
|
||||
|
||||
await saveImage(imageBlob, imageName)
|
||||
|
||||
return URL.createObjectURL(imageBlob)
|
||||
}
|
||||
}
|
||||
|
||||
// 这里的图片名后端定义的是 bg1.webp(大图), bg1-m.webp(预览图)
|
||||
const getCurrentBackground = async () => {
|
||||
if (
|
||||
showKUNGalgameBackground.value === '0' ||
|
||||
showKUNGalgameBackground.value === 'bg0' ||
|
||||
showKUNGalgameBackground.value === 'none'
|
||||
) {
|
||||
return 'none'
|
||||
} else if (showKUNGalgameBackground.value === '1007') {
|
||||
return `url(${showKUNGalgameCustomBackground.value})`
|
||||
} else {
|
||||
// TODO: 替换为后端接口
|
||||
return `url(/src/assets/images/bg/bg${showKUNGalgameBackground.value}.png)`
|
||||
}
|
||||
})
|
||||
if (showKUNGalgameBackground.value === 'bg1007') {
|
||||
return `${showKUNGalgameCustomBackground.value}`
|
||||
}
|
||||
// 获取图片的 blob url
|
||||
const url = await getBackgroundURL(showKUNGalgameBackground.value)
|
||||
return url
|
||||
}
|
||||
|
||||
// 获取所有图片的预览图,好像。。。min 比 thumbnail 萌一点
|
||||
// const getCurrentBackgroundMin = async () => {
|
||||
// let imageArray: string[] = []
|
||||
// for (let i = 0; i < 9; i++) {
|
||||
// const url = await getBackgroundURL(`bg${i}-m`)
|
||||
// imageArray.push(url)
|
||||
// }
|
||||
// return imageArray
|
||||
// }
|
||||
|
||||
// 恢复空白背景
|
||||
const restoreBackground = () => {
|
||||
showKUNGalgameBackground.value = 'bg0'
|
||||
}
|
||||
|
||||
export { getBackgroundURL, getCurrentBackground, restoreBackground }
|
||||
|
|
16
src/hooks/useLocalforage.ts
Normal file
16
src/hooks/useLocalforage.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import localforage from 'localforage'
|
||||
|
||||
// 保存图片
|
||||
const saveImage = async (imageData: Blob, imageName: string): Promise<void> => {
|
||||
await localforage.setItem(imageName, imageData)
|
||||
}
|
||||
// 获取图片
|
||||
const getImage = async (imageName: string): Promise<Blob | null> => {
|
||||
return await localforage.getItem(imageName)
|
||||
}
|
||||
// 删除图片
|
||||
const deleteImage = async (imageName: string): Promise<void> => {
|
||||
await localforage.removeItem(imageName)
|
||||
}
|
||||
|
||||
export { saveImage, getImage, deleteImage }
|
|
@ -1,16 +1,34 @@
|
|||
<!-- 先放一个 Layout 在这里,后面应该用得到 -->
|
||||
<script setup lang="ts">
|
||||
import { onMounted, watch, ref } from 'vue'
|
||||
// 导入动画
|
||||
import 'animate.css'
|
||||
|
||||
import { currBackground } from '@/hooks/useBackgroundPicture'
|
||||
|
||||
import { getCurrentBackground } from '@/hooks/useBackgroundPicture'
|
||||
import KUNGalgameTopBar from '@/components/top-bar/KUNGalgameTopBar.vue'
|
||||
|
||||
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
|
||||
storeToRefs(useKUNGalgameSettingsStore())
|
||||
|
||||
const imageURL = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
imageURL.value = await getCurrentBackground()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => [showKUNGalgameBackground.value, showKUNGalgameCustomBackground.value],
|
||||
async () => {
|
||||
imageURL.value = await getCurrentBackground()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- #default 是 v-slot 的简写,route 就是路由,Component 是一个 v-node -->
|
||||
<div class="app" :style="{ backgroundImage: currBackground }">
|
||||
<div class="app" :style="{ backgroundImage: `url(${imageURL})` }">
|
||||
<div class="top-bar">
|
||||
<KUNGalgameTopBar />
|
||||
</div>
|
||||
|
|
|
@ -81,7 +81,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||
},
|
||||
},
|
||||
|
||||
// KUNGalgame 403 TODO:
|
||||
// KUNGalgame 403
|
||||
{
|
||||
name: '403',
|
||||
path: '/kungalgame403',
|
||||
|
|
|
@ -70,15 +70,14 @@ onBeforeRouteLeave(async (to, from, next) => {
|
|||
|
||||
<!-- 版权 -->
|
||||
<KUNGalgameFooter style="margin: 0 auto; padding-top: 10px" />
|
||||
<span style="margin: 0 auto; color: var(--kungalgame-font-color-3)"
|
||||
>Editor powered by quill</span
|
||||
>
|
||||
<span style="margin: 0 auto; color: var(--kungalgame-font-color-3)">
|
||||
Editor powered by quill
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.root {
|
||||
margin-top: 20px;
|
||||
height: calc(100vh - 65px);
|
||||
min-height: 1000px;
|
||||
display: flex;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
import { Icon } from '@iconify/vue'
|
||||
|
||||
const props = defineProps(['data'])
|
||||
|
||||
// TODO: 后端接口字段名还未定,不能确定
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -118,8 +118,10 @@ const handleClickComment = (
|
|||
<!-- 顶部左侧名字 -->
|
||||
<div class="name">
|
||||
{{ `${comment.c_user.name} ${$tm('topic.content.comment')}` }}
|
||||
<!-- 跳转到用户主页 TODO: -->
|
||||
<a href="#">{{ comment.to_user.name }}</a>
|
||||
<!-- 跳转到用户主页 -->
|
||||
<RouterLink :to="`/kungalgamer/${comment.to_user.uid}/info`">
|
||||
{{ comment.to_user.name }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
<!-- 顶部右侧点赞、踩 -->
|
||||
<div class="operate">
|
||||
|
|
Loading…
Reference in a new issue