From 05604dcff2d7dd67826538c05e05dd94eb631545 Mon Sep 17 00:00:00 2001 From: mole404 <248403041+mole404@users.noreply.github.com> Date: Fri, 2 Oct 2026 23:02:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(viewer):=20=E5=AE=89=E5=8D=93=20Chromium=20?= =?UTF-8?q?=E4=B8=8A=E7=9C=8B=E5=9B=BE=E6=8E=A7=E4=BB=B6=E8=A7=A6=E6=91=B8?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E9=94=99=E4=B9=B1=20=E2=80=94=E2=80=94=20?= =?UTF-8?q?=E6=8B=A6=E6=8E=89=E9=87=8D=E5=A4=8D=E7=9A=84=20touch*=20?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:iOS 手机端手势完全正常,安卓(Edge/Chrome)看大图时切图极难触发、放大与拖动也常出问题。 真因(真 Chromium 实测的事件计数与 id):一次单指滑动同时收到 pointerdown ×1 与 touchstart ×1, 两者用的是**不同的 id 体系**(pointerdown: pointerId=5 / touchstart: touch.identifier=0)。 Viewer 的 pointerdown 里: if (options.zoomOnTouch && options.zoomable && Object.keys(pointers).length > 1) action = ACTION_ZOOM; 于是同一根手指被记成两个键 ⇒ 被判定成「两根手指捏合」⇒ 动作误派成 ZOOM,切图/平移都不对。 iOS 上两套 id 恰好同值(WebKit 的 pointerId 就是 touch identifier)⇒ 只有一个键 ⇒ 一切正常, 这正解释了为什么只有安卓坏。 修法:在看图容器那层用**捕获阶段**把 touch* 停掉,只留 pointer 一套(捏合缩放照旧走 pointer 路径)。 只影响 .viewer-container 内部,页面其它地方的触摸不受影响。 验收(本机模拟):一刀切图仍正常 ✓;两指捏合仍可用(图片宽 351 → 1193)✓;jsdom 9 套件全绿 ✓。 注:本机模拟复现不出该 bug(模拟器不是真安卓),但上面的事件计数与 id 差异是实测的, 实际效果请老师在安卓真机上确认。 --- Dockerfile | 4 ++-- patches/ios-longpress.patch | 2 +- src/resources/views/user/images.blade.php | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 693dc9c..01f2999 100644 --- a/Dockerfile +++ b/Dockerfile @@ -165,7 +165,7 @@ RUN php -r "file_exists('.env') || copy('.env.example', '.env');" \ RUN printf '%s\n' \ 'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./public/js/context-js/context-js.js' \ 'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./resources/js/context-js.js' \ - '27e13507a629aa3ae9f21496a6cf0ebf ./resources/views/user/images.blade.php' \ + 'cfaad16720f1646fda4426b832e12122 ./resources/views/user/images.blade.php' \ | md5sum -c - \ && grep -q "assetVersion('js/context-js/context-js.js')" ./resources/views/user/images.blade.php \ && grep -q 'isIOSWebKit' ./public/js/context-js/context-js.js \ @@ -208,7 +208,7 @@ RUN APP_SRC_MD5=$(find app config routes -type f -print0 2>/dev/null | sort -z | "fork_sha=${FORK_SHA}" \ "lsky_commit=${LSKY_COMMIT}" \ "context_js_md5=c0e513ec8e93fd81b34b3c6de5cf5eb8" \ - "images_blade_md5=27e13507a629aa3ae9f21496a6cf0ebf" \ + "images_blade_md5=cfaad16720f1646fda4426b832e12122" \ "app_src_md5=${APP_SRC_MD5}" \ "app_js_md5=${APP_JS_MD5}" \ "app_css_md5=${APP_CSS_MD5}" \ diff --git a/patches/ios-longpress.patch b/patches/ios-longpress.patch index 1a363b1..af8f9b9 100644 --- a/patches/ios-longpress.patch +++ b/patches/ios-longpress.patch @@ -52,7 +52,7 @@ # 三个文件各自的 md5(与 Dockerfile「自证 2」里的期望值一致): # c0e513ec8e93fd81b34b3c6de5cf5eb8 src/resources/js/context-js.js # c0e513ec8e93fd81b34b3c6de5cf5eb8 src/public/js/context-js/context-js.js -# 27e13507a629aa3ae9f21496a6cf0ebf src/resources/views/user/images.blade.php +# cfaad16720f1646fda4426b832e12122 src/resources/views/user/images.blade.php # # 上游原文件 md5(改动前,供比对): # c8e57f6232848ca8277341ddf1a3a7a6 resources/js/context-js.js diff --git a/src/resources/views/user/images.blade.php b/src/resources/views/user/images.blade.php index e83d493..a69be59 100644 --- a/src/resources/views/user/images.blade.php +++ b/src/resources/views/user/images.blade.php @@ -547,6 +547,20 @@ class="relative inline-flex h-4 w-7 shrink-0 items-center rounded-full bg-brand * (教训:第三方控件遇到根节点 zoom,就把它那层缩回去,别逐条路径打补丁。) */ + /* 安卓 Chromium 专属问题:它会**同时**派发 touch* 和 pointer* 两套事件,而 Viewer 把 + * 同一个手指记成两个键(touch.identifier vs pointerId)——实测 pointerId=5 / touchId=0 + * 不同值。于是它内部 `Object.keys(pointers).length > 1` 成立,把动作误判成 ACTION_ZOOM + * (以为是两根手指捏合)⇒ 手机上切图/放大/拖动全都不稳。iOS 上两套 id 恰好同值,所以没事。 + * 修法:在看图容器这层用**捕获阶段**把 touch* 拦下,不让它到 Viewer —— 只留 pointer 一套, + * 捏合缩放照旧走 pointer 路径。只影响看图控件内部,页面其它地方的触摸不受影响。 */ + ['touchstart', 'touchmove', 'touchend', 'touchcancel'].forEach(type => { + document.addEventListener(type, (e) => { + if (e.target instanceof Element && e.target.closest('.viewer-container')) { + e.stopPropagation(); + } + }, true); + }); + $photos.justifiedGallery(gridConfigs); let albumsInfinite = null;