ImgViewer
图片查看器,提供两种形态:
<ImgViewer />页面内嵌缩略图,支持单张或数组形式的图片源,叠加删除/触发层imgViewer.show()命令式浮窗放大预览,可拖动、无遮罩、不阻塞背景交互
旧版 ImgViewerZoom 已在 0.6.0 移除
连带卸载 viewerjs / v-viewer。全屏 / 浮窗式放大请改用 imgViewer.show()。
Anatomy
ImgViewer页面内嵌的图片容器,接受 string | File | 数组ImgViewerDeletehover 显示的删除按钮覆盖层,点击事件由外部处理
imgViewer命令式浮窗预览 helper:show / close / 只读响应式 stateFloatOpenerFloat 通用浮窗挂载点,在应用 root 挂一次。imgViewer.show 内部通过 float.show 把图片业务组件挂到这个栈中
缩略图(<ImgViewer />)
基本用法
显示单张图片
带删除按钮
叠加 Delete 按钮
通过默认 slot 叠加 ImgViewerDelete。
点击缩略图打开浮窗预览
<ImgViewer /> 不再内置放大按钮,需要放大请铺一个透明触发层调用 imgViewer.show()(见下方浮窗预览)。
点击缩略图打开浮窗
铺一个透明 button 调用 imgViewer.show()。
浮窗预览(imgViewer.show)
浮窗式图片预览,不遮罩、不抢焦点、不阻塞背景交互——形态类似 picture-in-picture。支持滚轮缩放、平移、多图切换、缩略图栏。
全局单例:再次 imgViewer.show 自动关闭上一个浮窗(触发其 onClose),同一时间只能存在一个预览实例。
演示页已挂载 <FloatOpener />
本页脚本顶部已渲染 <FloatOpener />,点击下方按钮即可打开浮窗。自己接入时必须在应用 root 显式挂一次(Nuxt 通过 @tripo3d/design/nuxt module 自动注册)。
单图预览
imgViewer.show(单值)
可拖拽放大缩小
imgViewer.show(src, { resizable: true })
启用后主图区右下角出现拖拽手柄,可整窗方形放大缩小(默认关闭)。
多图预览
数组 + 默认 index
多图时浮窗显示左右翻页按钮 + 底部缩略图栏。
通过点击项定位
替代手写 arr.indexOf(item):target 选项让组件在数组里查 index。
imgViewer.show(images, { target })
点击下方按钮,浮窗将打开第 3 张图。
持有 close 句柄 + onClose
show 返回 close 闭包;旧 close 在新 show 触发后自动 noop。
保留 close 句柄
点击「打开」后,可通过「程序化关闭」主动关闭。
联动响应式 state
imgViewer.isOpen / currentIndex / currentImage 是 Readonly<Ref<...>>。模板里使用前先在 setup 顶层赋值,Vue 3 的自动解包仅对 setup 顶层 ref 生效。
读取 isOpen / currentIndex
先打开图组,再观察下方实时变化。
false-1不要写 v-if="imgViewer.isOpen"
对象属性访问绕过 Vue 模板的 ref 自动解包,会拿到 ref 对象本身(永远 truthy)。务必先 const isOpen = imgViewer.isOpen 再用。
路由切换自动关闭
imgViewer 不绑定路由,业务侧自行 watch:
<script setup lang="ts">
import { imgViewer } from '@tripo3d/design';
const route = useRoute();
watch(() => route.fullPath, () => imgViewer.close());
</script>交互行为
| 动作 | 结果 |
|---|---|
| 拖动标题栏 | 移动浮窗(按钮、图片区由 .cancel-drag class 排除,不参与窗口拖动) |
| 滚轮 | 阶跃缩放 ±0.25,范围 [0.5, 2] |
| 右下角 +/- | 同滚轮,按钮触发 |
| 右下角手柄 | 拖拽整窗方形放大缩小(仅 resizable: true 时显示);边界自动收敛保证手柄不越出可视区 |
| 拖图 | 缩放 > 1 时启用,自动 clamp 不出 viewport |
| 左右翻页 | 多图时显示,自动重置缩放/位移 |
| 缩略图 | 多图时底部显示,点击切换;当前项自动 scrollIntoView 居中 |
| 关闭按钮 | 触发 onClose,关闭浮窗 |
不响应:ESC 全局键盘、点击外部、route/store 联动。需要这些联动请在应用层自行 watch + imgViewer.close()。
单例语义
const close1 = imgViewer.show(a, { onClose: () => console.log('a closed') });
const close2 = imgViewer.show(b); // 输出 'a closed',浮窗内容变 b
close1(); // noop(已被 close2 替代)
close2(); // 真正关闭 b实现细节:imgViewer 用固定 float key 实现单例 —— 内部组件 <ImageViewer /> 实例不卸载,连续 show 只是切换模块 state,浮窗原地替换内容(无 fade-out / fade-in 抖动)。 旧 close 闭包内部带 token 校验,被新 show 替代后调用变 noop——不会误关后续打开的浮窗。
API
<ImgViewer /> Props
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
src | string | File | Array<string | File> | — | 图片源,支持单图或数组 |
class | string | — | 容器 class |
alt | string | — | 图片替代文本。不传 → 不输出 alt 属性(保持当前行为);显式传 "" → alt=""(装饰性图片,屏幕阅读器跳过)。多图时所有 |
loading | "lazy" | "eager" | — | 图片加载策略。不传 → 不输出 loading 属性(浏览器默认 eager);传 "lazy" → 延迟加载 |
<ImgViewer /> Slots
| 插槽 | 作用域 | 说明 |
|---|---|---|
default | — | 操作层,用于叠加 ImgViewerDelete 或自定义触发区 |
<ImgViewerDelete />
无额外 Props,hover 时显示删除按钮覆盖层,点击事件由父组件处理。
imgViewer 命令式 API
| 方法 | 签名 | 说明 |
|---|---|---|
imgViewer.show | (src, options?) => () => void | 打开浮窗,返回 close 闭包;再次 show 自动关闭上一个并触发其 onClose |
imgViewer.close | () => void | 关闭当前活动浮窗(不持有 close 句柄时使用) |
imgViewer.show 选项
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
initialIndex | number | 0 | 默认打开的图片索引,越界 / 负数自动 clamp |
target | string | File | — | 替代手动 indexOf:传任一图,组件在数组里查 index |
onClose | () => void | — | 关闭时触发一次(含被新 show 替代的场景) |
initialPosition | { x?: number; y?: number } | — | 本次打开的初始位置(仅接受坐标对象);缺值/未传则走默认 center 居中。x / y 缺失轴自动居中 |
resizable | boolean | false | 启用后主图区右下角显示拖拽手柄,可整窗方形放大缩小;边界按浮窗位置与窗口可视区动态收敛,保证手柄不越出屏幕 |
imgViewer 只读响应式
| 字段 | 类型 | 说明 |
|---|---|---|
imgViewer.isOpen | Readonly<Ref<boolean>> | 当前是否有活动浮窗 |
imgViewer.currentIndex | Readonly<Ref<number>> | 当前展示的图片索引,未打开时 -1 |
imgViewer.currentImage | Readonly<Ref<string | null>> | 当前图片 URL(File 已 resolve 为 ObjectURL) |
SSR
imgViewer.show / close 在 SSR 环境(globalThis.window === undefined)下是 noop:show 返回空 close,close 直接返回。<FloatOpener /> 内部用 <Teleport to="body">,仅在客户端 hydrate 后挂载,不影响 SSR 渲染。