Skip to content

ImgViewer ​

图片查看器,提供两种形态:

  • <ImgViewer /> 页面内嵌缩略图,支持单张或数组形式的图片源,叠加删除/触发层
  • imgViewer.show() 命令式浮窗放大预览,可拖动、无遮罩、不阻塞背景交互

旧版 ImgViewerZoom 已在 0.6.0 移除

连带卸载 viewerjs / v-viewer。全屏 / 浮窗式放大请改用 imgViewer.show()。

Anatomy ​

  • ImgViewer页面内嵌的图片容器,接受 string | File | 数组
    • ImgViewerDeletehover 显示的删除按钮覆盖层,点击事件由外部处理
  • imgViewer命令式浮窗预览 helper:show / close / 只读响应式 state
  • FloatOpenerFloat 通用浮窗挂载点,在应用 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

先打开图组,再观察下方实时变化。

isOpen: false
currentIndex: -1

不要写 v-if="imgViewer.isOpen"

对象属性访问绕过 Vue 模板的 ref 自动解包,会拿到 ref 对象本身(永远 truthy)。务必先 const isOpen = imgViewer.isOpen 再用。

路由切换自动关闭 ​

imgViewer 不绑定路由,业务侧自行 watch:

vue
<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()。

单例语义 ​

ts
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 ​

名称 类型 默认值 说明
srcstring | File | Array<string | File>—图片源,支持单图或数组
classstring—容器 class
altstring—图片替代文本。不传 → 不输出 alt 属性(保持当前行为);显式传 "" → 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 选项 ​

名称 类型 默认值 说明
initialIndexnumber0默认打开的图片索引,越界 / 负数自动 clamp
targetstring | File—替代手动 indexOf:传任一图,组件在数组里查 index
onClose() => void—关闭时触发一次(含被新 show 替代的场景)
initialPosition{ x?: number; y?: number }—本次打开的初始位置(仅接受坐标对象);缺值/未传则走默认 center 居中。x / y 缺失轴自动居中
resizablebooleanfalse启用后主图区右下角显示拖拽手柄,可整窗方形放大缩小;边界按浮窗位置与窗口可视区动态收敛,保证手柄不越出屏幕

imgViewer 只读响应式 ​

字段类型说明
imgViewer.isOpenReadonly<Ref<boolean>>当前是否有活动浮窗
imgViewer.currentIndexReadonly<Ref<number>>当前展示的图片索引,未打开时 -1
imgViewer.currentImageReadonly<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 渲染。

基于 MIT 协议发布(内部使用)