提交 82eb9b37 authored 作者: 龙菲's avatar 龙菲

增加移动端单页显示

上级 49dfc88f
<template> <template>
<div class="book-reader"> <div class="book-reader"
@touchstart="handleTouchStart"
@touchend="handleTouchEnd">
<div v-if="loading" class="loading-overlay"> <div v-if="loading" class="loading-overlay">
<div class="loader"></div> <div class="loader"></div>
<p>正在加载图片...</p> <p>正在加载图片...</p>
...@@ -10,7 +12,8 @@ ...@@ -10,7 +12,8 @@
<div v-for="(page, index) in processedPages" :key="index" :class="['page', `p${index + 1}`, { <div v-for="(page, index) in processedPages" :key="index" :class="['page', `p${index + 1}`, {
'hard': !page.isWide && index % 2 === 0, 'hard': !page.isWide && index % 2 === 0,
'odd': !page.isWide && index % 2 !== 0, 'odd': !page.isWide && index % 2 !== 0,
'even': !page.isWide && index % 2 === 1 'even': !page.isWide && index % 2 === 1,
'mobile': isMobile
}]"> }]">
<img <img
:data-page-index="index" :data-page-index="index"
...@@ -65,6 +68,10 @@ ...@@ -65,6 +68,10 @@
<!-- 替换为 vue-easy-lightbox 预览组件 --> <!-- 替换为 vue-easy-lightbox 预览组件 -->
<vue-easy-lightbox :visible="showViewer" :imgs="previewImages" :index="currentImageIndex" <vue-easy-lightbox :visible="showViewer" :imgs="previewImages" :index="currentImageIndex"
@hide="showViewer = false" /> @hide="showViewer = false" />
<div class="mobile-gesture-hint" v-if="isMobile">
左右滑动切换页面
</div>
</div> </div>
</template> </template>
...@@ -93,6 +100,9 @@ const loadingQueue = ref(new Set()) ...@@ -93,6 +100,9 @@ const loadingQueue = ref(new Set())
const maxConcurrentLoads = 5 const maxConcurrentLoads = 5
const imageCache = ref(new Map()) const imageCache = ref(new Map())
const loadingTimeouts = ref(new Map()) const loadingTimeouts = ref(new Map())
const isMobile = ref(false)
const touchStartX = ref(0)
const touchStartY = ref(0)
// 修改预览相关的状态 // 修改预览相关的状态
const showViewer = ref(false) const showViewer = ref(false)
...@@ -102,6 +112,35 @@ const previewImages = ref([]) ...@@ -102,6 +112,35 @@ const previewImages = ref([])
// 将 processedPages 改为普通数据属性 // 将 processedPages 改为普通数据属性
const processedPages = ref([]) const processedPages = ref([])
// 检测是否为移动设备
const checkMobile = () => {
isMobile.value = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}
// 处理触摸事件
const handleTouchStart = (e) => {
if (!isMobile.value) return
touchStartX.value = e.touches[0].clientX
touchStartY.value = e.touches[0].clientY
}
const handleTouchEnd = (e) => {
if (!isMobile.value) return
const touchEndX = e.changedTouches[0].clientX
const touchEndY = e.changedTouches[0].clientY
const deltaX = touchEndX - touchStartX.value
const deltaY = touchEndY - touchStartY.value
// 如果水平滑动距离大于垂直滑动距离,且大于50px,则触发翻页
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
if (deltaX > 0) {
previous()
} else {
next()
}
}
}
// 修改处理页面的函数,只处理必要的属性 // 修改处理页面的函数,只处理必要的属性
const processPages = (pages) => { const processPages = (pages) => {
return pages.map((item, index) => ({ return pages.map((item, index) => ({
...@@ -196,11 +235,29 @@ const initBook = async () => { ...@@ -196,11 +235,29 @@ const initBook = async () => {
if (!magazine.value || !processedPages.value.length) return if (!magazine.value || !processedPages.value.length) return
destroyTurn() destroyTurn()
checkMobile()
const viewportWidth = window.innerWidth const viewportWidth = window.innerWidth
const viewportHeight = window.innerHeight const viewportHeight = window.innerHeight
const pageWidth = Math.min(600, viewportWidth / 2 - 50)
const pageHeight = Math.min(800, viewportHeight - 100) // 移动端使用不同的尺寸计算
let pageWidth, pageHeight
if (isMobile.value) {
// 移动端:宽度等于设备宽度减去边距
pageWidth = viewportWidth - 20 // 左右各留10px边距
// 高度按比例计算(假设标准比例为 4:3)
pageHeight = (pageWidth * 4) / 3
// 确保高度不超过视口高度
if (pageHeight > viewportHeight - 100) { // 上下各留50px边距
pageHeight = viewportHeight - 100
// 重新计算宽度以保持比例
pageWidth = (pageHeight * 3) / 4
}
} else {
// 桌面端保持原有逻辑
pageWidth = Math.min(600, viewportWidth / 2 - 50)
pageHeight = Math.min(800, viewportHeight - 100)
}
await nextTick() await nextTick()
...@@ -234,10 +291,11 @@ const initBook = async () => { ...@@ -234,10 +291,11 @@ const initBook = async () => {
} }
}) })
// 移动端使用单页显示
$magazine.turn({ $magazine.turn({
width: pageWidth * 2, width: isMobile.value ? pageWidth : pageWidth * 2,
height: pageHeight, height: pageHeight,
display: 'double', display: isMobile.value ? 'single' : 'double',
acceleration: false, acceleration: false,
gradients: true, gradients: true,
elevation: 50, elevation: 50,
...@@ -623,6 +681,7 @@ const handleSmallImageClick = (smallImage, pageNum) => { ...@@ -623,6 +681,7 @@ const handleSmallImageClick = (smallImage, pageNum) => {
background-color: #333; background-color: #333;
position: relative; position: relative;
background-image: url('../assets/images/bg2.jpg'); background-image: url('../assets/images/bg2.jpg');
touch-action: pan-y pinch-zoom;
} }
.magazine-viewport { .magazine-viewport {
...@@ -633,7 +692,6 @@ const handleSmallImageClick = (smallImage, pageNum) => { ...@@ -633,7 +692,6 @@ const handleSmallImageClick = (smallImage, pageNum) => {
align-items: center; align-items: center;
position: relative; position: relative;
overflow: hidden !important; overflow: hidden !important;
/* 强制隐藏滚动条 */
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
...@@ -956,4 +1014,68 @@ const handleSmallImageClick = (smallImage, pageNum) => { ...@@ -956,4 +1014,68 @@ const handleSmallImageClick = (smallImage, pageNum) => {
padding: 8px 16px; padding: 8px 16px;
border-radius: 4px; border-radius: 4px;
} }
.mobile-gesture-hint {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
}
.mobile-gesture-hint.show {
opacity: 1;
}
@media (max-width: 768px) {
.controls {
bottom: 10px;
padding: 6px 12px;
gap: 10px;
}
.previous-button,
.next-button,
.zoom-in,
.zoom-out {
width: 30px;
height: 30px;
}
.previous-button svg,
.next-button svg,
.zoom-in svg,
.zoom-out svg {
width: 18px;
height: 18px;
}
.magazine {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
max-width: 100vw;
}
.page {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
}
.page-image {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
height: 100% !important;
object-fit: contain;
}
}
</style> </style>
\ No newline at end of file
/*
* @Author: 龙菲 1373694886@qq.com
* @Date: 2025-04-22 22:24:25
* @LastEditors: 龙菲 1373694886@qq.com
* @LastEditTime: 2025-04-24 22:37:56
* @FilePath: \pic-reader\vite.config.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from 'node:url'
...@@ -40,6 +48,8 @@ export default defineConfig({ ...@@ -40,6 +48,8 @@ export default defineConfig({
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api/, '')
} }
} },
host:'0.0.0.0',
port:8089,
} }
}) })
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论