提交 6265f8f0 authored 作者: 龙菲's avatar 龙菲

恢复最初版本

上级 e5f127db
......@@ -6,14 +6,13 @@
<!-- <meta name="viewport" content="width=1050, user-scalable=no" /> -->
<meta
name="viewport"
content="width=100vw, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>PDF阅读器</title>
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.5.3/modernizr.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/turn.js/4.1.0/turn.min.js"></script> -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/turn.js/4.1.0/turn.html4.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/turn.js/4.1.0/zoom.min.js"></script>
<!-- 引入jQuery -->
<!-- <script src="/js/jquery.min.1.7.js"></script> -->
<!-- 引入Turn.js -->
<!-- <script src="/js/turn.js"></script> -->
</head>
<body>
<div id="app"></div>
......
......@@ -9,8 +9,10 @@
"version": "0.0.0",
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@rollup/plugin-inject": "^5.0.5",
"axios": "^1.8.4",
"element-plus": "^2.9.8",
"lodash": "^4.17.21",
"modernizr": "^3.6.0",
"turn.js": "^1.0.5",
"vant": "^4.9.19",
......@@ -1017,11 +1019,31 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/plugin-inject": {
"version": "5.0.5",
"resolved": "https://registry.npmmirror.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz",
"integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
......@@ -1329,8 +1351,7 @@
"node_modules/@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="
},
"node_modules/@types/lodash": {
"version": "4.17.16",
......@@ -4606,8 +4627,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
......@@ -5430,7 +5450,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"engines": {
"node": ">=12"
},
......@@ -5944,7 +5963,7 @@
"version": "4.40.0",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.40.0.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
"dev": true,
"devOptional": true,
"dependencies": {
"@types/estree": "1.0.7"
},
......@@ -8829,11 +8848,20 @@
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
},
"@rollup/plugin-inject": {
"version": "5.0.5",
"resolved": "https://registry.npmmirror.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz",
"integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==",
"requires": {
"@rollup/pluginutils": "^5.0.1",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.3"
}
},
"@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
"dev": true,
"requires": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
......@@ -9001,8 +9029,7 @@
"@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="
},
"@types/lodash": {
"version": "4.17.16",
......@@ -11955,8 +11982,7 @@
"picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="
},
"pify": {
"version": "2.3.0",
......@@ -12311,7 +12337,7 @@
"version": "4.40.0",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.40.0.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
"dev": true,
"devOptional": true,
"requires": {
"@rollup/rollup-android-arm-eabi": "4.40.0",
"@rollup/rollup-android-arm64": "4.40.0",
......
......@@ -10,8 +10,10 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@rollup/plugin-inject": "^5.0.5",
"axios": "^1.8.4",
"element-plus": "^2.9.8",
"lodash": "^4.17.21",
"modernizr": "^3.6.0",
"turn.js": "^1.0.5",
"vant": "^4.9.19",
......
<template>
<div class="app">
<!-- <FileUpload @upload-complete="handleUploadComplete" /> -->
<!-- <List /> -->
<!-- <BookReader
v-if="documentPages.length > 0"
:pages="documentPages"
showExitMessage
/> -->
<!-- <div v-else class="empty-state">
请上传PDF文件开始阅读
</div> -->
<router-view />
<!-- <flip-book /> -->
</div>
</template>
<script setup>
// import { ref } from "vue";
// import { getDocumentDetail } from "@/api";
// const documentPages = ref([]);
// const fetchDocumentDetail = async (id) => {
// try {
// const res = await getDocumentDetail(id);
// documentPages.value = res.map((item) => {
// return {
// ...item,
// page_url:
// import.meta.env.VITE_API_BASE_URL + "/static/" + item.page_url,
// images: item.images.map((img) => {
// return {
// ...img,
// url: import.meta.env.VITE_API_BASE_URL + "/static/" + img.url,
// };
// }),
// };
// });
// } catch (error) {
// // 错误已经被 request 拦截器处理,这里可以添加额外的错误处理逻辑
// }
// };
// onMounted(() => {
// fetchDocumentDetail("ececa7473dea4d3a4448c754068139fc");
// });
// const handleUploadComplete = (data) => {
// images.value = data.page_images.map(img => img.path)
// }
import FlipBook from "@/components/FlipBook/index.vue";
</script>
<style>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -10,15 +10,16 @@ declare module 'vue' {
export interface GlobalComponents {
BookMarks: typeof import('./components/GuideMobile/bookMarks.vue')['default']
BookReader: typeof import('./components/BookReader/index.vue')['default']
copy: typeof import('./components/BookReader/index copy.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElRow: typeof import('element-plus/es')['ElRow']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
FileUpload: typeof import('./components/FileUpload.vue')['default']
Guide: typeof import('./components/GuideMobile/guide.vue')['default']
FlipBook: typeof import('./components/FlipBook/index.vue')['default']
GuideMobile: typeof import('./components/GuideMobile/index.vue')['default']
GuidePc: typeof import('./components/GuidePc/index.vue')['default']
IconCommunity: typeof import('./components/icons/IconCommunity.vue')['default']
......@@ -29,7 +30,9 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SvgIcon: typeof import('./components/SvgIcon/index.vue')['default']
Test: typeof import('./components/Test/index.vue')['default']
VanCell: typeof import('vant/es')['Cell']
VanIcon: typeof import('vant/es')['Icon']
VanList: typeof import('vant/es')['List']
VanNavBar: typeof import('vant/es')['NavBar']
VanPopup: typeof import('vant/es')['Popup']
......
......@@ -53,6 +53,20 @@
</div>
</div>
</div>
<!-- <div
class="left-button mobile-page-button"
@click="previous"
v-if="isMobile"
>
<van-icon name="arrow-left" />
</div>
<div
class="right-button mobile-page-button"
@click="next"
v-if="isMobile"
>
<van-icon name="arrow" />
</div> -->
</div>
<!-- <div v-if="showExitMessage" class="exit-message">按 ESC 键退出阅读</div> -->
......@@ -82,32 +96,54 @@
<div class="footer">
<el-row :gutter="10" class="tab-bar">
<el-col :class="['left', { isMobile }]" :span="isMobile ? 24 : 8">
<svg-icon name="menu" size="20" @click="showGuide"></svg-icon>
<svg-icon
name="zoom-in"
size="20"
v-if="!isMobile"
@click="zoomOut"
></svg-icon>
<svg-icon
name="zoom-out"
size="20"
v-if="!isMobile"
@click="zoomIn"
></svg-icon>
<el-tooltip content="目录" placement="top" effect="dark">
<svg-icon name="menu" size="20" @click="showGuide"></svg-icon>
</el-tooltip>
<el-tooltip content="缩小" placement="top" effect="dark">
<svg-icon
name="zoom-in"
size="20"
v-if="!isMobile"
@click="zoomOut"
></svg-icon>
</el-tooltip>
<el-tooltip content="放大" placement="top" effect="dark">
<svg-icon
name="zoom-out"
size="20"
v-if="!isMobile"
@click="zoomIn"
></svg-icon>
</el-tooltip>
<!-- 修改音量图标部分 -->
<svg-icon
:name="isMuted ? 'volume-mute' : 'volume-high'"
size="20"
@click="toggleMute"
/>
<el-tooltip
:content="isMuted ? '开启音效' : '关闭音效'"
placement="top"
effect="dark"
>
<svg-icon
:name="isMuted ? 'volume-mute' : 'volume-high'"
size="20"
@click="toggleMute"
/>
</el-tooltip>
</el-col>
<el-col class="center" :span="8">
<svg-icon name="to-first" size="30" @click="toFirst"></svg-icon>
<svg-icon name="to-left" size="22" @click="previous"></svg-icon>
<el-tooltip content="跳转到第一页" placement="top" effect="dark">
<svg-icon name="to-first" size="30" @click="toFirst"></svg-icon>
</el-tooltip>
<el-tooltip content="跳转上一页" placement="top" effect="dark">
<svg-icon name="to-left" size="22" @click="previous"></svg-icon>
</el-tooltip>
<div class="page-count" v-if="!isMobile">{{ currentPage }}</div>
<svg-icon name="to-right" size="22" @click="next"></svg-icon>
<svg-icon name="to-end" size="30" @click="toEnd"></svg-icon>
<el-tooltip content="跳转下一页" placement="top" effect="dark">
<svg-icon name="to-right" size="22" @click="next"></svg-icon>
</el-tooltip>
<el-tooltip content="跳转到最后一页" placement="top" effect="dark">
<svg-icon name="to-end" size="30" @click="toEnd"></svg-icon>
</el-tooltip>
</el-col>
<el-col class="right" :span="8">
<!-- <svg-icon name="download" size="20"></svg-icon> -->
......@@ -120,10 +156,13 @@
<script setup>
import $ from "jquery";
import "turn.js";
// import turn from "@/assets/js/turn.js";
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from "vue";
import VueEasyLightbox from "vue-easy-lightbox";
import GuideMobile from "../GuideMobile/index.vue";
import audioFlip from "@/assets/audio/flip.mp3";
import throttle from "lodash/throttle";
import debounce from "lodash/debounce";
const props = defineProps({
pages: {
type: Array,
......@@ -143,7 +182,7 @@ const zoomLevel = ref(1);
const isInitialized = ref(false);
const imageObserver = ref(null);
const loadingQueue = ref(new Set());
const maxConcurrentLoads = 5;
const maxConcurrentLoads = 3;
const imageCache = ref(new Map());
const loadingTimeouts = ref(new Map());
const isMobile = ref(false);
......@@ -183,7 +222,7 @@ const handleTouchStart = (e) => {
touchStartY.value = e.touches[0].clientY;
};
const handleTouchEnd = (e) => {
const handleTouchEnd = throttle((e) => {
if (!isMobile.value) return;
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
......@@ -198,7 +237,7 @@ const handleTouchEnd = (e) => {
next();
}
}
};
});
// 修改处理页面的函数,只处理必要的属性
const processPages = (pages) => {
......@@ -281,24 +320,25 @@ const loadVisiblePages = async (currentPage) => {
const totalPages = $magazine.turn("pages");
// 加载当前页、上一页、下一页和下下页
const startPage = Math.max(1, currentPage - 1);
const startPage = Math.max(1, currentPage - 2);
const endPage = Math.min(totalPages, currentPage + 2);
const loadTasks = [];
for (let i = startPage; i <= endPage; i++) {
const pageIndex = i - 1;
if (
pageIndex >= 0 &&
pageIndex < processedPages.value.length &&
!processedPages.value[pageIndex].isLoaded
) {
loadTasks.push(loadImage(pageIndex));
}
}
const highPriority = [currentPage, currentPage + 1]; // 优先加载当前和下一页
// const loadTasks = [];
// for (let i = startPage; i <= endPage; i++) {
// const pageIndex = i - 1;
// if (
// pageIndex >= 0 &&
// pageIndex < processedPages.value.length &&
// !processedPages.value[pageIndex].isLoaded
// ) {
// loadTasks.push(loadImage(pageIndex));
// }
// }
try {
loading.value = true;
await Promise.all(loadTasks);
await Promise.all(highPriority.map(loadImage));
} catch (error) {
console.error("加载页面失败:", error);
} finally {
......@@ -373,16 +413,15 @@ const initBook = async () => {
width: isMobile.value ? pageWidth : pageWidth * 2,
height: pageHeight,
display: isMobile.value ? "single" : "double",
acceleration: true,
acceleration: false,
gradients: true,
elevation: 100,
elevation: 80,
duration: 800,
autoCenter: true,
turnCorners: "bl,br",
page: 1,
when: {
turning: async (event, page) => {
loading.value = true;
await loadVisiblePages(page);
// 确保加载完成后才继续翻页
setTimeout(() => {
......@@ -478,8 +517,8 @@ const handleImageError = async (index) => {
}
};
const next = () => {
if (magazine.value && isInitialized.value) {
const next = throttle(() => {
if (magazine.value && isInitialized.value && !loading.value) {
const $magazine = $(magazine.value);
const currentPage = $magazine.turn("page");
const nextPage = currentPage + 1;
......@@ -492,10 +531,10 @@ const next = () => {
$magazine.turn("next", { duration: 1500 });
}, 100);
}
};
});
const previous = () => {
if (magazine.value && isInitialized.value) {
const previous = throttle(() => {
if (magazine.value && isInitialized.value && !loading.value) {
const $magazine = $(magazine.value);
const currentPage = $magazine.turn("page");
const prevPage = currentPage - 1;
......@@ -508,7 +547,7 @@ const previous = () => {
$magazine.turn("previous", { duration: 1500 });
}, 100);
}
};
});
const toFirst = () => {
const firstPage = props.pages[0].page_num;
......@@ -837,7 +876,7 @@ const showGuide = () => {
position: relative;
overflow: hidden;
background-color: white; // 视口背景
contain: strict; // 启用CSS Contain隔离布局
.magazine {
background-color: white; // 书本背景
}
......@@ -852,7 +891,7 @@ const showGuide = () => {
align-items: center;
background-color: #333;
position: relative;
background-image: url("@/assets/images/bg3.jpg");
background-image: url("@/assets/images/bg4.png");
background-size: 100% 100%;
touch-action: pan-y pinch-zoom;
}
......@@ -879,23 +918,6 @@ const showGuide = () => {
transform-style: preserve-3d;
}
// .magazine::after {
// content: "";
// position: absolute;
// top: 0;
// left: 50%;
// width: 1px;
// height: 100%;
// background: linear-gradient(
// to bottom,
// rgba(0, 0, 0, 0.1) 0%,
// rgba(0, 0, 0, 0.2) 50%,
// rgba(0, 0, 0, 0.1) 100%
// );
// z-index: 10;
// pointer-events: none;
// }
.page {
background-color: white;
position: absolute;
......@@ -910,100 +932,6 @@ const showGuide = () => {
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.05);
}
// .page:before {
// content: "";
// position: absolute;
// width: 100px;
// height: 100px;
// bottom: 0;
// z-index: 10;
// }
// .page.odd:before {
// right: 0;
// background: linear-gradient(315deg, rgba(0, 0, 0, 0.2) 0%, transparent 50%);
// }
// .page.even:before {
// left: 0;
// background: linear-gradient(45deg, rgba(0, 0, 0, 0.2) 0%, transparent 50%);
// }
// .page-image {
// width: 100%;
// height: 100%;
// object-fit: contain;
// pointer-events: none;
// visibility: visible !important;
// // backface-visibility: hidden;
// transform-style: preserve-3d;
// transform: translate3d(0, 0, 0);
// }
// .exit-message {
// position: fixed;
// top: 20px;
// left: 50%;
// transform: translateX(-50%);
// background: rgba(0, 0, 0, 0.5);
// color: white;
// padding: 10px 20px;
// border-radius: 4px;
// z-index: 1000;
// }
// .page.wide-page {
// width: 200% !important;
// left: 0 !important;
// z-index: 5 !important;
// }
// .page.wide-page.isHidden {
// display: none !important;
// }
// .wide-image {
// width: 100%;
// height: 100%;
// object-fit: contain;
// }
/* 确保宽图页面的阴影效果 */
// .page.wide-page::after {
// content: "";
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// bottom: 0;
// box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.2);
// pointer-events: none;
// z-index: 1;
// }
/* 角落悬停效果 */
// .page.hover::before {
// content: "";
// position: absolute;
// width: 100px;
// height: 100px;
// pointer-events: none;
// z-index: 10;
// transition: all 0.3s ease;
// }
// .page.hover:nth-child(odd)::before {
// right: 0;
// bottom: 0;
// background: linear-gradient(315deg, rgba(0, 0, 0, 0.2) 0%, transparent 80%);
// }
// .page.hover:nth-child(even)::before {
// left: 0;
// bottom: 0;
// background: linear-gradient(45deg, rgba(0, 0, 0, 0.2) 0%, transparent 80%);
// }
/* 缩放状态样式 */
.magazine.zoomed {
cursor: move;
......@@ -1052,6 +980,27 @@ const showGuide = () => {
/* 防止图片本身接收点击事件 */
}
.mobile-page-button {
position: absolute;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
background-color: #444;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
}
.left-button {
left: 4px;
}
.right-button {
right: 4px;
}
.footer {
background-color: #444;
padding: 0 20px;
......
<template>
<div class="back"></div>
<div id="canvas">
<div class="previousPage" @click="previousPage"></div>
<div class="nextPage" @click="nextPage"></div>
<div class="magazine-viewport">
<div class="container">
<div class="magazine"></div>
</div>
</div>
</div>
</template>
<script>
import { onMounted, ref, onBeforeUnmount } from "vue";
// import $ from "jquery";
import { isChrome, addPage, disableControls } from "./magazine";
// import "/js/modernizr.2.5.3.min.js";
// import "/js/hash.js";
// import "/js/turn.js";
// import "/js/turn.html4.min.js";
// import "/js/zoom.min.js";
// import "/js/magazine.js";
const $ = window.$;
export default {
name: "Flipbook",
setup() {
const magazine = ref(null);
// Initialize the flipbook once the component is mounted
onMounted(() => {
setTimeout(() => {
loadApp();
}, 1000);
});
// Clean up on component unmount
onBeforeUnmount(() => {
if (magazine.value) {
$(magazine.value).turn("destroy");
}
});
const nextPage = () => {
$(magazine.value).turn("next");
};
const previousPage = () => {
$(magazine.value).turn("previous");
};
// Function to load the flipbook app
function loadApp() {
debugger;
$("#canvas").fadeIn(1000);
const flipbook = $(".magazine");
if (flipbook.width() === 0 || flipbook.height() === 0) {
setTimeout(loadApp, 10);
return;
}
console.log(window.screen.width);
console.log(window.screen.height);
let w, h;
if (window.screen.width > window.screen.height) {
w = $(".magazine-viewport").parent().width();
h = $(window).height();
if (w === 0) {
w = ((2482 * 2) / 3368) * h;
}
const w1 = ((2482 * 2) / 3368) * h;
const h1 = (3368 / (2482 * 2)) * w;
if (w1 > w) {
h = h1;
} else {
w = w1;
}
$(".magazine-viewport").width(w).height(h);
$(".magazine").width(w).height(h);
$(window).resize(() => {
let w = $(".magazine-viewport").parent().width();
let h = $(window).height();
if (w === 0) {
w = ((2482 * 2) / 3368) * h;
}
const w1 = ((2482 * 2) / 3368) * h;
const h1 = (3368 / (2482 * 2)) * w;
if (w1 > w) {
h = h1;
} else {
w = w1;
}
$(".magazine-viewport").width(w).height(h);
$(".magazine").width(w).height(h);
});
initBook("double");
} else {
w = $(".magazine-viewport").parent().width();
h = $(window).height();
if (w === 0) {
w = (2482 / 3368) * h;
}
const w1 = (2482 / 3368) * h;
const h1 = (3368 / 2482) * w;
if (w1 > w) {
h = h1;
} else {
w = w1;
}
$(".magazine-viewport").width(w).height(h);
$(".magazine").width(w).height(h);
$(window).resize(() => {
const w = $(".magazine-viewport").parent().width();
const h = $(window).height();
if (w === 0) {
w = (2482 / 3368) * h;
}
const w1 = (2482 / 3368) * h;
const h1 = (3368 / 2482) * w;
if (w1 > w) {
h = h1;
} else {
w = w1;
}
$(".magazine-viewport").width(w).height(h);
$(".magazine").width(w).height(h);
});
initBook("single");
}
}
// Function to initialize the flipbook
function initBook(display) {
const flipbook = $(".magazine");
flipbook.turn({
width: $(".magazine-viewport").parent().width(),
height: $(window).height(),
duration: 1000,
display,
acceleration: !isChrome(),
gradients: true,
autoCenter: true,
elevation: 50,
pages: 73,
when: {
turning: function (event, page, view) {
const book = $(this);
const currentPage = book.turn("page");
const pages = book.turn("pages");
Hash.go(`page/${page}`).update();
disableControls(page);
},
turned: function (event, page, view) {
disableControls(page);
$(this).turn("center");
if (page === 1) {
$(this).turn("peel", "br");
}
},
missing: function (event, pages) {
for (let i = 0; i < pages.length; i++) addPage(pages[i], $(this));
},
},
});
}
return {
magazine,
nextPage,
previousPage,
};
},
};
</script>
<style scoped>
/* Add your custom styles for the flipbook here */
@import "./magazine.css";
</style>
body {
overflow: hidden;
/* background: url('../pics/wood.png'); */
margin: 0;
padding: 0;
}
.back {
width: 100vw;
height: 100vh;
position: absolute;
left: 0;
top: 0;
z-index: 55;
/* background: url('../pics/wood.png'); */
background: rgba(2, 0, 34, 0.986);
}
#canvas {
position: absolute;
background: url('@/assets/images/bg4.png') repeat-x bottom center;
}
/*上一页*/
.previousPage {
width: 33%;
height: 60%;
position: absolute;
bottom: 0%;
left: 17%;
z-index: 999999;
/* background-color: aqua; */
background: transparent !important;
}
/*下一页*/
.nextPage {
width: 33%;
height: 60%;
position: absolute;
bottom: 0%;
left: 50%;
z-index: 999999;
/* background-color: aqua; */
background: transparent !important;
}
.magazine-viewport {
position: absolute;
}
.magazine-viewport .container {
z-index: 666;
position: absolute;
top: 54%;
left: 50%;
width: 1400px;
height: 781px;
margin: auto;
}
.magazine-viewport .magazine {
width: 1400px;
height: 781px;
left: -661px;
top: -300px;
}
.magazine-viewport .page {
width: 700px;
height: 781px;
background-color: white;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.magazine-viewport .zoomer .region {
display: none;
}
.magazine .region {
position: absolute;
overflow: hidden;
background: #0066FF;
opacity: 0.2;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
-ms-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
cursor: pointer;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
.magazine .region:hover {
opacity: 0.5;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
}
.magazine .region.zoom {
opacity: 0.01;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=1)";
filter: alpha(opacity=1);
}
.magazine .region.zoom:hover {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
.magazine .page {
-webkit-box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
-ms-box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
-o-box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
}
.magazine-viewport .page img {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0;
}
.magazine .even .gradient {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: -webkit-gradient(linear, left top, right top, color-stop(0.95, rgba(0, 0, 0, 0)), color-stop(1, rgba(0, 0, 0, 0.2)));
background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.2) 100%);
background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.2) 100%);
background-image: -ms-linear-gradient(left, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.2) 100%);
background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.2) 100%);
background-image: linear-gradient(left, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.2) 100%);
}
.magazine .odd .gradient {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: -webkit-gradient(linear, right top, left top, color-stop(0.95, rgba(0, 0, 0, 0)), color-stop(1, rgba(0, 0, 0, 0.15)));
background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.15) 100%);
background-image: -moz-linear-gradient(right, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.15) 100%);
background-image: -ms-linear-gradient(right, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.15) 100%);
background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.15) 100%);
background-image: linear-gradient(right, rgba(0, 0, 0, 0) 95%, rgba(0, 0, 0, 0.15) 100%);
}
.magazine-viewport .zoom-in .even .gradient,
.magazine-viewport .zoom-in .odd .gradient {
display: none;
}
.magazine-viewport .loader {
/* background-image: url(../pics/loader.gif); */
width: 22px;
height: 22px;
position: absolute;
top: 280px;
left: 219px;
}
.magazine-viewport .shadow {
-webkit-transition: -webkit-box-shadow 0.5s;
-moz-transition: -moz-box-shadow 0.5s;
-o-transition: -webkit-box-shadow 0.5s;
-ms-transition: -ms-box-shadow 0.5s;
-webkit-box-shadow: 0 0 20px #000;
-moz-box-shadow: 0 0 20px #000;
-o-box-shadow: 0 0 20px #000;
-ms-box-shadow: 0 0 20px #000;
box-shadow: 0 0 20px #000;
}
.next-button {
width: 59px;
height: 59px;
position: absolute;
top: 50%;
/* background: url('../pics/arrows.png') -59px 0; */
right: 10px;
z-index: 10;
}
.previous-button {
width: 59px;
height: 59px;
position: absolute;
top: 50%;
/* background-image: url('../pics/arrows.png'); */
z-index: 10;
}
.magazine-viewport .previous-button-hover {
background-position: 0 -59px;
cursor: pointer;
}
.magazine-viewport .next-button-hover {
background-position: -59px -59px;
cursor: pointer;
}
.magazine-viewport .previous-button-hover,
.magazine-viewport .previous-button-down {}
.magazine-viewport .previous-button-down,
.magazine-viewport .next-button-down {}
.magazine-viewport .next-button-hover,
.magazine-viewport .next-button-down {}
.magazine-viewport .zoom-in .next-button,
.magazine-viewport .zoom-in .previous-button {
display: none;
}
.animated {
-webkit-transition: margin-left 0.5s;
-moz-transition: margin-left 0.5s;
-ms-transition: margin-left 0.5s;
-o-transition: margin-left 0.5s;
transition: margin-left 0.5s;
}
.exit-message {
position: absolute;
top: 10px;
left: 0;
width: 100%;
height: 40px;
z-index: 10000;
}
.exit-message>div {
width: 140px;
height: 30px;
margin: auto;
background: rgba(0, 0, 0, 0.5);
text-align: center;
font: 12px arial;
line-height: 30px;
color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
-ms-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
}
.zoom-icon {
position: absolute;
z-index: 1000;
width: 22px;
height: 22px;
top: 10px;
right: 10px;
/* background-image: url(../pics/zoom-icons.png); */
background-size: 88px 22px;
}
.zoom-icon-in {
background-position: 0 0;
cursor: pointer;
}
.zoom-icon-in.zoom-icon-in-hover {
background-position: -22px 0;
cursor: pointer;
}
.zoom-icon-out {
background-position: -44px 0;
}
.zoom-icon-out.zoom-icon-out-hover {
background-position: -66px 0;
cursor: pointer;
}
.bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
\ No newline at end of file
/*
* Magazine sample
*/
function setArrows() {
setTimeout(function() {
var width = $(window).width();
var bookWidth = $(".magazine").width();
var arrowSize = $(".next-button").width();
var magaLeft = $(".magazine").offset().left;
// import window.$ from 'jquery'
export function setArrows() {
setTimeout(function () {
var width = window.$(window).width();
var bookWidth = window.$(".magazine").width();
var arrowSize = window.$(".next-button").width();
var magaLeft = window.$(".magazine").offset().left;
var nextLeft = (width - bookWidth - magaLeft - 60) / 2;
//alert("width "+width +"\nbookWidth :"+bookWidth +"\nmagaLeft:"+magaLeft+"\nnextLeft:"+nextLeft);
$('.next-button').animate({ "right": nextLeft }, 300);
window.window.$('.next-button').animate({ "right": nextLeft }, 300);
$('.previous-button').animate({ "left": nextLeft }, 300);
window.window.$('.previous-button').animate({ "left": nextLeft }, 300);
}, 100);
}
function addPage(page, book) {
export function addPage(page, book) {
var id, pages = book.turn('pages');
var element = $('<div />', {});
var element = window.window.$('<div />', {});
if (book.turn('addPage', element, page)) {
element.html('<div class="gradient"></div><div class="loader"></div>');
loadPage(page, element);
......@@ -28,43 +28,43 @@ function addPage(page, book) {
}
function loadPage(page, pageElement) {
export function loadPage(page, pageElement) {
pageElement.find('.loader').remove();
const imgPath = new URL(`../../assets/book/img_window.window.${page}.jpg`, import.meta.url).href;
// Create an image element
var img = $('<img />');
var img = window.$('<img />');
img.mousedown(function(e) {
img.mousedown(function (e) {
e.preventDefault();
});
img.load(function() {
img.load(function () {
// Set the size
$(this).css({
window.$(this).css({
width: '100%',
height: '100%'
});
// Add the image to the page after loaded
$(this).appendTo(pageElement);
window.$(this).appendTo(pageElement);
// Remove the loader indicator
pageElement.find('.loader').remove();
});
// Load the page
img.attr('src', 'book/img_' + page + '.jpg');
img.attr('src', imgPath);
}
function zoomTo(event) {}
export function zoomTo(event) { }
function addRegion(region, pageElement) {
export function addRegion(region, pageElement) {
var reg = $('<div />', {
'class': 'region ' + region['class']
}),
options = $('.magazine').turn('options'),
var reg = window.$('<div />', {
'class': 'region ' + region['class']
}),
options = window.$('.magazine').turn('options'),
pageWidth = options.width / 2,
pageHeight = options.height;
......@@ -73,26 +73,26 @@ function addRegion(region, pageElement) {
left: Math.round(region.x / pageWidth * 100) + '%',
width: Math.round(region.width / pageWidth * 100) + '%',
height: Math.round(region.height / pageHeight * 100) + '%'
}).attr('region-data', $.param(region.data || ''));
}).attr('region-data', window.$.param(region.data || ''));
reg.appendTo(pageElement);
}
// Process click on a region
function regionClick(event) {
export function regionClick(event) {
var region = $(event.target);
var region = window.$(event.target);
if (region.hasClass('region')) {
$('.magazine-viewport').data().regionClicked = true;
window.$('.magazine-viewport').data().regionClicked = true;
setTimeout(function() {
$('.magazine-viewport').data().regionClicked = false;
},
setTimeout(function () {
window.$('.magazine-viewport').data().regionClicked = false;
},
100);
var regionType = $.trim(region.attr('class').replace('region', ''));
var regionType = window.$.trim(region.attr('class').replace('region', ''));
return processRegion(region, regionType);
......@@ -103,30 +103,30 @@ function regionClick(event) {
// http://code.google.com/p/chromium/issues/detail?id=128488
function isChrome() {
export function isChrome() {
return navigator.userAgent.indexOf('Chrome') != -1;
}
function disableControls(page) {
if (page == 1) $('.previous-button').hide();
else $('.previous-button').show();
if (page == $('.magazine').turn('pages')) $('.next-button').hide();
else $('.next-button').show();
export function disableControls(page) {
if (page == 1) window.$('.previous-button').hide();
else window.$('.previous-button').show();
if (page == window.$('.magazine').turn('pages')) window.$('.next-button').hide();
else window.$('.next-button').show();
}
// Set the width and height for the viewport
function resizeViewport() {
export function resizeViewport() {
var width = $(window).width(),
height = $(window).height(),
options = $('.magazine').turn('options');
$('.magazine').removeClass('animated');
$('.magazine-viewport').css({
var width = window.$(window).width(),
height = window.$(window).height(),
options = window.$('.magazine').turn('options');
window.$('.magazine').removeClass('animated');
window.$('.magazine-viewport').css({
width: width,
height: height
}).zoom('resize');
setArrows();
if ($('.magazine').turn('zoom') == 1) {
if (window.$('.magazine').turn('zoom') == 1) {
var bound = calculateBound({
width: options.width,
height: options.height,
......@@ -135,59 +135,59 @@ function resizeViewport() {
});
if (bound.width % 2 !== 0) bound.width -= 1;
if (bound.width != $('.magazine').width() || bound.height != $('.magazine').height()) {
$('.magazine').turn('size', bound.width, bound.height);
if ($('.magazine').turn('page') == 1) $('.magazine').turn('peel', 'br');
if (bound.width != window.$('.magazine').width() || bound.height != window.$('.magazine').height()) {
window.$('.magazine').turn('size', bound.width, bound.height);
if (window.$('.magazine').turn('page') == 1) window.$('.magazine').turn('peel', 'br');
}
$('.magazine').css({
window.$('.magazine').css({
top: -bound.height / 2,
left: -bound.width / 2
});
}
var magazineOffset = $('.magazine').offset(),
boundH = height - magazineOffset.top - $('.magazine').height(),
marginTop = (boundH - $('.thumbnails > div').height()) / 2;
var magazineOffset = window.$('.magazine').offset(),
boundH = height - magazineOffset.top - window.$('.magazine').height(),
marginTop = (boundH - window.$('.thumbnails > div').height()) / 2;
if (marginTop < 0) {
$('.thumbnails').css({
window.$('.thumbnails').css({
height: 1
});
} else {
$('.thumbnails').css({
window.$('.thumbnails').css({
height: boundH
});
$('.thumbnails > div').css({
window.$('.thumbnails > div').css({
marginTop: marginTop
});
}
if (magazineOffset.top < $('.made').height()) $('.made').hide();
else $('.made').show();
if (magazineOffset.top < window.$('.made').height()) window.$('.made').hide();
else window.$('.made').show();
$('.magazine').addClass('animated');
window.$('.magazine').addClass('animated');
}
// Number of views in a flipbook
function numberOfViews(book) {
export function numberOfViews(book) {
return book.turn('pages') / 2 + 1;
}
// Current view in a flipbook
function getViewNumber(book, page) {
export function getViewNumber(book, page) {
return parseInt((page || book.turn('page')) / 2 + 1, 10);
}
// Width of the flipbook when zoomed in
function largeMagazineWidth() {
export function largeMagazineWidth() {
return 2214;
}
// Calculate the width and height of a square within another square
function calculateBound(d) {
export function calculateBound(d) {
var bound = {
width: d.width,
height: d.height
......@@ -203,4 +203,5 @@ function calculateBound(d) {
}
}
return bound;
}
\ No newline at end of file
}
/*
* @Author: 龙菲 1373694886@qq.com
* @Date: 2025-04-23 22:37:01
* @LastEditors: 龙菲 1373694886@qq.com
* @LastEditTime: 2025-04-23 22:41:24
* @FilePath: \pic-reader\src\utils\request.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import axios from 'axios';
import { ElMessage } from 'element-plus';
......@@ -67,7 +60,7 @@ service.interceptors.response.use(
} else {
ElMessage.error('请求配置错误');
}
return Promise.reject(error);
}
);
......
......@@ -103,7 +103,8 @@ onMounted(() => {
@media (max-width: 768px) {
.book-card-list {
padding: 20px;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
// grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) ;
grid-template-columns: repeat(3, 1fr) !important;
gap: 15px;
}
}
......
......@@ -9,6 +9,7 @@ import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver, VantResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
import inject from '@rollup/plugin-inject';
// https://vite.dev/config/
export default defineConfig(({ mode, command }) => {
......@@ -16,19 +17,20 @@ export default defineConfig(({ mode, command }) => {
return {
base: env.VITE_API_ROUTE_URL,
optimizeDeps: {
exclude: [
'modernizr',
'src/assets/js/modernizr.2.5.3.min.js'
]
},
build: {
rollupOptions: {
external: [
/modernizr/,
/requirejs/
]
}
include: ['jquery']
// exclude: [
// 'modernizr',
// 'src/assets/js/modernizr.2.5.3.min.js'
// ]
},
// build: {
// rollupOptions: {
// external: [
// /modernizr/,
// /requirejs/
// ]
// }
// },
plugins: [
vue(),
vueDevTools(),
......@@ -49,6 +51,10 @@ export default defineConfig(({ mode, command }) => {
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')], // SVG 存放路径
symbolId: 'icon-[name]'
}),
inject({
$: 'jquery',
jQuery: 'jquery',
})
],
resolve: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论