From 84f88cb4733844bcddc52dbcd33122117dd2a2be Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Tue, 29 Sep 2026 02:07:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=92=A4=E9=94=80=20ce07f4a=EF=BC=88lightbox?= =?UTF-8?q?=20=E6=89=8B=E6=9C=BA=E9=80=82=E9=85=8D=20+=20=E6=AD=A3?= =?UTF-8?q?=E6=96=87=E5=9B=BE=E9=A2=84=E8=A7=88=E5=A7=94=E6=89=98=EF=BC=89?= =?UTF-8?q?=EF=BC=9A=E7=9C=9F=E6=9C=BA=E4=B8=8A=E5=8F=8D=E5=A4=8D=E5=87=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=88=E6=92=91=E5=B1=8F/=E7=BC=A9?= =?UTF-8?q?=E6=94=BE=E9=94=99=E4=B9=B1=EF=BC=89=EF=BC=8C=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E5=88=B0=E5=8E=9F=E6=9C=89=E7=AE=80=E5=8D=95?= =?UTF-8?q?=E9=A2=84=E8=A7=88=EF=BC=9B=E4=BB=85=E4=BF=9D=E7=95=99=20lb-ope?= =?UTF-8?q?n=20=E9=9A=90=E8=97=8F=E5=90=B8=E9=A1=B6=E6=A0=8F=E7=9A=84?= =?UTF-8?q?=E4=BA=AE=E5=B8=A6=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.vue | 27 +--------- frontend/src/components/ImgLightbox.vue | 66 +++++-------------------- frontend/src/utils.js | 8 +-- 3 files changed, 16 insertions(+), 85 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 2eae261..54830c6 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -7,26 +7,9 @@ import ImgLightbox from './components/ImgLightbox.vue' import YohakuTop from './ui/yohaku/YohakuTop.vue' import YohakuFoot from './ui/yohaku/YohakuFoot.vue' import { site, setAdminScope } from './site' -import { openLightbox } from './lightbox' const route = useRoute() -// 正文图片点击预览(capture 阶段):时间线/详情页里 v-html 的正文图 -// 都没有自己的点击入口,这里统一接管。capture + stopPropagation 是为了 -// 压住整卡点击(时间线点图不该跳详情);配图网格有自己的 handler 不在 -// .prose 内,天然不受影响。lightbox 用 data-fullsrc 原图(thumbify 保留)。 -function onProseImgClick(e) { - const img = e.target - if (!img || img.tagName !== 'IMG') return - const scope = img.closest('.prose') - if (!scope || img.closest('.post-imgs') || img.closest('a')) return - const list = [...scope.querySelectorAll('img')].map((i) => i.dataset.fullsrc || i.currentSrc || i.src) - const cur = img.dataset.fullsrc || img.currentSrc || img.src - const idx = Math.max(0, list.indexOf(cur)) - e.stopPropagation() - openLightbox(list, idx) -} - // 正文代码块复制按钮(事件委托:复制按钮是 enhanceProse 注入的静态 HTML) function onCopyClick(e) { const btn = e.target.closest?.('.pre-copy') @@ -48,14 +31,8 @@ function onCopyClick(e) { setTimeout(() => (btn.textContent = '复制'), 1600) }) } -onMounted(() => { - document.addEventListener('click', onCopyClick) - document.addEventListener('click', onProseImgClick, true) -}) -onBeforeUnmount(() => { - document.removeEventListener('click', onCopyClick) - document.removeEventListener('click', onProseImgClick, true) -}) +onMounted(() => document.addEventListener('click', onCopyClick)) +onBeforeUnmount(() => document.removeEventListener('click', onCopyClick)) const isAdmin = computed(() => route.path.startsWith('/admin')) // vivid 只在公开前台生效:后台永远走 classic 那套(--admin-* token + 原 data-ui/data-theme), diff --git a/frontend/src/components/ImgLightbox.vue b/frontend/src/components/ImgLightbox.vue index 935b2c5..7c34c3f 100644 --- a/frontend/src/components/ImgLightbox.vue +++ b/frontend/src/components/ImgLightbox.vue @@ -3,59 +3,34 @@ import { onBeforeUnmount, watch } from 'vue' import { lightboxState as st, closeLightbox, stepLightbox } from '../lightbox' // 图片预览层:App.vue 全局挂一次。铺满全屏的暗底 + 居中大图, -// 多图时左右箭头 / 方向键 / 手机滑动切换,角标显示第几张;Esc / 点空白收起。 +// 多图时左右箭头 / 方向键切换,角标显示第几张;Esc / 点空白收起。 function onKey(e) { if (e.key === 'Escape') closeLightbox() if (e.key === 'ArrowLeft') stepLightbox(-1) if (e.key === 'ArrowRight') stepLightbox(1) } - -// 打开时锁住背景滚动(手机上尤其明显:否则手指滑动会带着页面一起动) -let prevOverflow = '' watch( () => st.open, (v) => { if (v) { window.addEventListener('keydown', onKey) - prevOverflow = document.body.style.overflowY - // 只锁纵向:整个 overflow 改 hidden 会覆盖样式表的 overflow-x: clip, - // 横向从「裁剪」变「可滚动容器」,手机上整页能被拖宽(真实事故) - document.body.style.overflowY = 'hidden' + // 吸顶栏带 backdrop-filter,真机上其合成层会盖在遮罩之上 + // (遮罩 z-index 更高也拦不住)——开预览时整个藏掉 document.body.classList.add('lb-open') } else { window.removeEventListener('keydown', onKey) - document.body.style.overflowY = prevOverflow document.body.classList.remove('lb-open') } } ) -onBeforeUnmount(() => { - window.removeEventListener('keydown', onKey) - document.body.style.overflowY = prevOverflow - document.body.classList.remove('lb-open') -}) - -// 手机滑动翻页:横向位移超 44px 且大于纵向位移才算一次滑动 -let touchX = 0 -let touchY = 0 -function onTouchStart(e) { - touchX = e.touches[0].clientX - touchY = e.touches[0].clientY -} -function onTouchEnd(e) { - const dx = e.changedTouches[0].clientX - touchX - const dy = e.changedTouches[0].clientY - touchY - if (Math.abs(dx) > 44 && Math.abs(dx) > Math.abs(dy) * 1.4 && st.list.length > 1) { - stepLightbox(dx < 0 ? 1 : -1) - } -} +onBeforeUnmount(() => window.removeEventListener('keydown', onKey))