fix(web): 图片预览缩放改显式 px,修 CSS zoom 被 flex max 夹回放不大 + bump 0.12.11
CSS zoom 对带 max-width/height:100% 的 flex item 无效(放大后被百分比 max 重新约束回去,视觉不变)。改为:以 scale=1 的贴合显示尺寸为基准缓存,缩放时 max:none + 显式 width/height = base × scale 像素,真正撑大布局让 body 出 滚动条;复位时清空还原自适应。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
31f46baaf6
commit
12171a4bdf
|
|
@ -21,6 +21,11 @@
|
||||||
|
|
||||||
## 已完成关键能力
|
## 已完成关键能力
|
||||||
|
|
||||||
|
### 2026-06-15 / 文件预览缩放改显式 px:修 CSS zoom 放不大
|
||||||
|
|
||||||
|
- 接上一条:CSS `zoom` 对带 `max-width/height:100%` 的 flex item 不生效 —— zoom 放大后被百分比 max 约束重新夹回,视觉无变化(用户实测"还是不能放大")。
|
||||||
|
- 改法(`web/static/js/preview.js` `_applyZoom`):以 scale=1 的贴合显示尺寸(`clientWidth/Height`)为基准缓存到 `z.baseW/baseH`,缩放时 `max-width/height:none` + 显式 `width/height = base × scale` px;复位时清空还原 CSS 自适应。显式 px 真正撑大布局,body 才出滚动条。bump 0.12.10 → 0.12.11。
|
||||||
|
|
||||||
### 2026-06-15 / 文件预览:修滚动穿透 + 图片 Ctrl+滚轮缩放
|
### 2026-06-15 / 文件预览:修滚动穿透 + 图片 Ctrl+滚轮缩放
|
||||||
|
|
||||||
- 现象:web 端文件预览弹框内滚滚轮,事件冒泡到背景把对话列表也滚了(scroll chaining);且图片预览无缩放手段。
|
- 现象:web 端文件预览弹框内滚滚轮,事件冒泡到背景把对话列表也滚了(scroll chaining);且图片预览无缩放手段。
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||||
# 改版本只动这一行。
|
# 改版本只动这一行。
|
||||||
__version__ = "0.12.10"
|
__version__ = "0.12.11"
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,28 @@ let _fpCurrentRel = null;
|
||||||
const _zoomState = new WeakMap(); // bodyEl -> { img, scale, badge, timer }
|
const _zoomState = new WeakMap(); // bodyEl -> { img, scale, badge, timer }
|
||||||
|
|
||||||
function _applyZoom(z) {
|
function _applyZoom(z) {
|
||||||
// 用 CSS zoom(非 transform):zoom 改变布局盒尺寸,放大后 body 才会出滚动条能看溢出部分
|
const img = z.img;
|
||||||
z.img.style.zoom = z.scale === 1 ? "" : z.scale;
|
if (z.scale === 1) {
|
||||||
z.img.style.cursor = z.scale === 1 ? "zoom-in" : "zoom-out";
|
// 复位:还原 CSS 里的 max-width/height:100% 自适应贴合
|
||||||
|
img.style.maxWidth = "";
|
||||||
|
img.style.maxHeight = "";
|
||||||
|
img.style.width = "";
|
||||||
|
img.style.height = "";
|
||||||
|
img.style.cursor = "zoom-in";
|
||||||
|
} else {
|
||||||
|
// 以 scale=1 时的"贴合显示"尺寸为基准,给显式像素尺寸。
|
||||||
|
// 不用 CSS zoom:图片是带 max-width/height:100% 的 flex item,zoom 放大后会被
|
||||||
|
// 百分比 max 约束重新夹回 → 视觉不变;显式 px + max:none 才真正撑大并让 body 出滚动条。
|
||||||
|
if (!z.baseW) {
|
||||||
|
z.baseW = img.clientWidth || img.naturalWidth;
|
||||||
|
z.baseH = img.clientHeight || img.naturalHeight;
|
||||||
|
}
|
||||||
|
img.style.maxWidth = "none";
|
||||||
|
img.style.maxHeight = "none";
|
||||||
|
img.style.width = Math.round(z.baseW * z.scale) + "px";
|
||||||
|
img.style.height = Math.round(z.baseH * z.scale) + "px";
|
||||||
|
img.style.cursor = "zoom-out";
|
||||||
|
}
|
||||||
z.badge.textContent = Math.round(z.scale * 100) + "%";
|
z.badge.textContent = Math.round(z.scale * 100) + "%";
|
||||||
z.badge.classList.add("show");
|
z.badge.classList.add("show");
|
||||||
if (z.timer) clearTimeout(z.timer);
|
if (z.timer) clearTimeout(z.timer);
|
||||||
|
|
@ -84,7 +103,7 @@ function _makeImageZoomable(bodyEl, img) {
|
||||||
const badge = document.createElement("div");
|
const badge = document.createElement("div");
|
||||||
badge.className = "zoom-badge"; // 挂到 card 而非 body,放大后 body 滚动时徽标不跟着滚走
|
badge.className = "zoom-badge"; // 挂到 card 而非 body,放大后 body 滚动时徽标不跟着滚走
|
||||||
card.appendChild(badge);
|
card.appendChild(badge);
|
||||||
const z = { img, scale: 1, badge, timer: null };
|
const z = { img, scale: 1, badge, timer: null, baseW: 0, baseH: 0 };
|
||||||
_zoomState.set(bodyEl, z);
|
_zoomState.set(bodyEl, z);
|
||||||
img.style.cursor = "zoom-in";
|
img.style.cursor = "zoom-in";
|
||||||
img.addEventListener("dblclick", () => { z.scale = 1; _applyZoom(z); });
|
img.addEventListener("dblclick", () => { z.scale = 1; _applyZoom(z); });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue