fix: web书籍部分图片加载失败

This commit is contained in:
Xwite
2023-04-16 20:13:45 +08:00
parent 97d75c1484
commit 9ee0c363e6
12 changed files with 61 additions and 63 deletions
+1
View File
@@ -4,6 +4,7 @@
"ComponentPublicInstance": true, "ComponentPublicInstance": true,
"ComputedRef": true, "ComputedRef": true,
"EffectScope": true, "EffectScope": true,
"ElLoading": true,
"ElMessage": true, "ElMessage": true,
"InjectionKey": true, "InjectionKey": true,
"PropType": true, "PropType": true,
+1
View File
@@ -5,6 +5,7 @@
export {} export {}
declare global { declare global {
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const ElLoading: typeof import('element-plus/es')['ElLoading']
const ElMessage: typeof import('element-plus/es')['ElMessage'] const ElMessage: typeof import('element-plus/es')['ElMessage']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed'] const computed: typeof import('vue')['computed']
+5 -5
View File
@@ -3,7 +3,7 @@
<div class="wrapper"> <div class="wrapper">
<div <div
class="book" class="book"
v-for="book in props.books" v-for="book in books"
:key="book.bookUrl" :key="book.bookUrl"
@click="handleClick(book)" @click="handleClick(book)"
> >
@@ -22,7 +22,7 @@
<div class="author"> <div class="author">
{{ book.author }} {{ book.author }}
</div> </div>
<div class="tags" v-show="props.isSearch"> <div class="tags" v-show="isSearch">
<el-tag <el-tag
v-for="tag in book.kind?.split(',').slice(0, 2)" v-for="tag in book.kind?.split(',').slice(0, 2)"
:key="tag" :key="tag"
@@ -30,16 +30,16 @@
{{ tag }} {{ tag }}
</el-tag> </el-tag>
</div> </div>
<div class="update-info" v-show="!props.isSearch"> <div class="update-info" v-show="!isSearch">
<div class="dot">•</div> <div class="dot">•</div>
<div class="size">共{{ book.totalChapterNum }}章</div> <div class="size">共{{ book.totalChapterNum }}章</div>
<div class="dot">•</div> <div class="dot">•</div>
<div class="date">{{ dateFormat(book.lastCheckTime) }}</div> <div class="date">{{ dateFormat(book.lastCheckTime) }}</div>
</div> </div>
</div> </div>
<div class="intro" v-show="props.isSearch">{{ book.intro }}</div> <div class="intro" v-show="isSearch">{{ book.intro }}</div>
<div class="dur-chapter" v-show="!props.isSearch"> <div class="dur-chapter" v-show="!isSearch">
已读:{{ book.durChapterTitle }} 已读:{{ book.durChapterTitle }}
</div> </div>
<div class="last-chapter">最新:{{ book.latestChapterTitle }}</div> <div class="last-chapter">最新:{{ book.latestChapterTitle }}</div>
+13 -5
View File
@@ -1,9 +1,10 @@
<template> <template>
<div v-for="(para, index) in props.carray" :key="index"> <div v-for="(para, index) in carray" :key="index">
<img <img
class="full" class="full"
v-if="/^\s*<img[^>]*src[^>]+>$/.test(para)" v-if="/^\s*<img[^>]*src[^>]+>$/.test(para)"
:src="getImageSrc(para)" :src="getImageSrc(para)"
@error.once="proxyImage"
loading="lazy" loading="lazy"
/> />
<p v-else :style="style" v-html="para" /> <p v-else :style="style" v-html="para" />
@@ -12,8 +13,10 @@
<script setup> <script setup>
import config from "../plugins/config"; import config from "../plugins/config";
import { getImageFromLegado, isLegadoUrl } from "../plugins/utils";
const store = useBookStore(); const store = useBookStore();
const props = defineProps(["carray"]); defineProps(["carray"]);
const fontFamily = computed(() => { const fontFamily = computed(() => {
if (store.config.font >= 0) { if (store.config.font >= 0) {
@@ -30,10 +33,15 @@ const style = computed(() => {
return style; return style;
}); });
function getImageSrc(content) { const getImageSrc = (content) => {
const imgPattern = /<img[^>]*src="([^"]*(?:"[^>]+\})?)"[^>]*>/; const imgPattern = /<img[^>]*src="([^"]*(?:"[^>]+\})?)"[^>]*>/;
return content.match(imgPattern)[1]; const src = content.match(imgPattern)[1];
} if (isLegadoUrl(src)) return getImageFromLegado(src);
return src;
};
const proxyImage = (event) => {
event.target.src = getImageFromLegado(event.target.src);
};
watch(fontSize, () => { watch(fontSize, () => {
store.setShowContent(false); store.setShowContent(false);
+6 -6
View File
@@ -11,12 +11,12 @@
</template> </template>
<script setup> <script setup>
const { source } = defineProps(['source']) defineProps(["source"]);
const store = useSourceStore() const store = useSourceStore();
const { errorPushSources } = storeToRefs(store) const { errorPushSources } = storeToRefs(store);
const handleSourceClick = source => { const handleSourceClick = (source) => {
store.changeCurrentSource(source) store.changeCurrentSource(source);
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.error { .error {
+6 -4
View File
@@ -30,7 +30,7 @@
</div> </div>
<el-checkbox-group id="source-list" v-model="sourceSelect"> <el-checkbox-group id="source-list" v-model="sourceSelect">
<virtual-list <virtual-list
style="height: 100%; overflow-y: auto; overflow-x: hidden;" style="height: 100%; overflow-y: auto; overflow-x: hidden"
:data-key="(source) => source.bookSourceUrl || source.sourceUrl" :data-key="(source) => source.bookSourceUrl || source.sourceUrl"
:data-sources="sourcesFiltered" :data-sources="sourcesFiltered"
:data-component="SourceItem" :data-component="SourceItem"
@@ -42,7 +42,7 @@
<script setup> <script setup>
import { Folder, Delete, Download, Search } from "@element-plus/icons-vue"; import { Folder, Delete, Download, Search } from "@element-plus/icons-vue";
import { isSourceContains } from "../utils/souce"; import { isSourceContains } from "../utils/souce";
import VirtualList from 'vue3-virtual-scroll-list'; import VirtualList from "vue3-virtual-scroll-list";
import SourceItem from "./SourceItem.vue"; import SourceItem from "./SourceItem.vue";
const store = useSourceStore(); const store = useSourceStore();
@@ -98,7 +98,10 @@ const importSourceFile = () => {
}; };
const outExport = () => { const outExport = () => {
const exportFile = document.createElement("a"); const exportFile = document.createElement("a");
let sources = sourceSelect.value.length === 0 ? sourcesFiltered.value : sourceSelect.value, let sources =
sourceSelect.value.length === 0
? sourcesFiltered.value
: sourceSelect.value,
sourceType = isBookSource.value ? "BookSource" : "RssSource"; sourceType = isBookSource.value ? "BookSource" : "RssSource";
exportFile.download = `${sourceType}_${Date() exportFile.download = `${sourceType}_${Date()
@@ -129,5 +132,4 @@ const outExport = () => {
width: 100%; width: 100%;
} }
} }
</style> </style>
+2 -6
View File
@@ -1,7 +1,7 @@
<template> <template>
<el-tabs id="source-edit"> <el-tabs id="source-edit">
<el-tab-pane <el-tab-pane
v-for="{ name, children } in tabsData" v-for="{ name, children } in Object.values(config)"
:label="name" :label="name"
:key="name" :key="name"
> >
@@ -59,11 +59,7 @@
<script setup> <script setup>
const store = useSourceStore(); const store = useSourceStore();
defineProps(["config"]);
const props = defineProps(["config"]);
const tabsData = Object.values(props.config);
const { currentSource } = storeToRefs(store); const { currentSource } = storeToRefs(store);
</script> </script>
+20 -18
View File
@@ -73,25 +73,27 @@ import { isInvaildSource } from "../utils/souce";
const store = useSourceStore(); const store = useSourceStore();
const pull = () => { const pull = () => {
const loadingMsg = ElMessage({ const loadingMsg = ElMessage({
message: '加载中……', message: "加载中……",
showClose: true, showClose: true,
duration: 0 duration: 0,
}) });
API.getSources().then(({ data }) => { API.getSources()
if (data.isSuccess) { .then(({ data }) => {
store.changeTabName("editList"); if (data.isSuccess) {
store.saveSources(data.data); store.changeTabName("editList");
ElMessage({ store.saveSources(data.data);
message: `成功拉取${data.data.length}条源`, ElMessage({
type: "success", message: `成功拉取${data.data.length}条源`,
}); type: "success",
} else { });
ElMessage({ } else {
message: data.errorMsg ?? "后端错误", ElMessage({
type: "error", message: data.errorMsg ?? "后端错误",
}); type: "error",
} });
}).finally(() => loadingMsg.close()); }
})
.finally(() => loadingMsg.close());
}; };
const push = () => { const push = () => {
+1 -5
View File
@@ -1,7 +1,7 @@
import { formatDate } from "@vueuse/shared"; import { formatDate } from "@vueuse/shared";
export const isLegadoUrl = (/** @type {string} */ url) => export const isLegadoUrl = (/** @type {string} */ url) =>
/,\s*\s*\{/.test(url) || /,\s*\{/.test(url) ||
!( !(
url.startsWith("http") || url.startsWith("http") ||
url.startsWith("data:") || url.startsWith("data:") ||
@@ -11,10 +11,6 @@ export const isLegadoUrl = (/** @type {string} */ url) =>
* @param {string} src * @param {string} src
*/ */
export function getImageFromLegado(src) { export function getImageFromLegado(src) {
//返回阅读代理的图片链接 已经代理的或者dataurl返回传入值
if (!isLegadoUrl(src)) {
return src;
}
return ( return (
(import.meta.env.VITE_API || location.origin) + (import.meta.env.VITE_API || location.origin) +
"/image?path=" + "/image?path=" +
+4 -7
View File
@@ -85,7 +85,7 @@
<div class="title" :index="data.index" v-if="showContent"> <div class="title" :index="data.index" v-if="showContent">
{{ data.title }} {{ data.title }}
</div> </div>
<chapter-content :carray="data.content" v-if="showContent"/> <chapter-content :carray="data.content" v-if="showContent" />
</div> </div>
<div class="loading" ref="loading"></div> <div class="loading" ref="loading"></div>
<div class="bottom-bar" ref="bottom"></div> <div class="bottom-bar" ref="bottom"></div>
@@ -105,7 +105,7 @@ const loadingSerive = ref(null);
const content = ref(); const content = ref();
watch(showLoading, (loading) => { watch(showLoading, (loading) => {
if (!loading) return loadingSerive.value?.close(); if (!loading) return loadingSerive.value?.close();
loadingSerive.value = ElLoading.service({ loadingSerive.value = ElLoading.service({
target: content.value, target: content.value,
spinner: loadingSvg, spinner: loadingSvg,
@@ -139,15 +139,13 @@ const {
showContent, showContent,
} = storeToRefs(store); } = storeToRefs(store);
const { chapterPos, index: chapterIndex} = toRefs(store.readingBook); const { chapterPos, index: chapterIndex } = toRefs(store.readingBook);
const { theme, infiniteLoading } = toRefs(store.config); const { theme, infiniteLoading } = toRefs(store.config);
// 主题部分 // 主题部分
const bodyColor = computed(() => settings.themes[theme.value].body); const bodyColor = computed(() => settings.themes[theme.value].body);
const chapterColor = computed( const chapterColor = computed(() => settings.themes[theme.value].content);
() => settings.themes[theme.value].content
);
const popupColor = computed(() => settings.themes[theme.value].popup); const popupColor = computed(() => settings.themes[theme.value].popup);
const readWidth = computed(() => { const readWidth = computed(() => {
@@ -215,7 +213,6 @@ watch(popupColor, (color) => {
rightBarTheme.value.background = color; rightBarTheme.value.background = color;
}); });
watchEffect(() => { watchEffect(() => {
if (chapterData.value.length > 0) { if (chapterData.value.length > 0) {
store.setContentLoading(false); store.setContentLoading(false);
+2 -2
View File
@@ -147,7 +147,7 @@ const searchBook = () => {
() => { () => {
showLoading.value = false; showLoading.value = false;
if (books.value.length == 0) { if (books.value.length == 0) {
ElMessage.info("搜索结果为空") ElMessage.info("搜索结果为空");
} }
} }
); );
@@ -224,7 +224,7 @@ const fetchBookShelfData = () => {
showLoading.value = false; showLoading.value = false;
store.setConnectType("danger"); store.setConnectType("danger");
store.setConnectStatus("连接失败"); store.setConnectStatus("连接失败");
ElMessage.error("后端连接失败") ElMessage.error("后端连接失败");
store.setNewConnect(false); store.setNewConnect(false);
throw error; throw error;
}); });
-5
View File
@@ -34,10 +34,5 @@ if (/bookSource/i.test(location.href)) {
width: 360px; width: 360px;
margin-right: 20px; margin-right: 20px;
} }
#loading {
position: fixed;
top: 100px;
left: 90vw;
}
} }
</style> </style>