Repository: Tencent/tdesign-mobile-vue (ts)

Issue:
【ImageViewer组件升级】任务单
> 我们最终的目标是希望mobile vue、mobile react、miniprogram **三端可以共用一套样式文件、一套示例文档**，而目前 miniprogram 端的完成度最高，因此在做组件升级时，我们需要和小程序端的同名组件保持一样的 DOM结构，以复用一套样式，组件示例文件命名也应和小程序端命名保持一致，以复用一套示例文档。



## 开发指引
[mobile vue：组件升级指引](https://github.com/Tencent/tdesign-mobile-vue/wiki/mobile-vue%EF%BC%9A%E7%BB%84%E4%BB%B6%E5%8D%87%E7%BA%A7%E6%8C%87%E5%BC%95)

## 任务清单
- [ ] DOM 结构对齐小程序端
- [ ] 改用 V2文件夹下样式
- [ ] 新增 deleteBtn 属性
- [ ] 新增 delete 事件



## 组件新视觉
> 设计稿：【腾讯 CoDesign】TDesign移动端设计稿](https://codesign.qq.com/s/RG6X0kXNObZxEPB)

#### 新视觉样式如下：
<img width="375" alt="Preview 图片预览 移动端展示" src="https://user-images.githubusercontent.com/51158141/233979914-95fde683-faad-47ec-b71a-83cd9498c08e.png">

## 激励

参与共建的开发者，将可以获得 [TDesign 周边](https://github.com/Tencent/tdesign/wiki/TDesign-%E5%91%A8%E8%BE%B9)（贴纸、鼠标垫、工卡套等）；

成为核心贡献者，将会拥有 TDesign 专属头像。


Pull request:
feat(image-viewer): finish new version
<!--
首先，感谢你的贡献！😄
请阅读并遵循 [TDesign 贡献指南](https://github.com/Tencent/tdesign/blob/main/docs/contributing.md)，填写以下 pull request 的信息。
PR 在维护者审核通过后会合并，谢谢！
-->

### 🤔 这个 PR 的性质是？

- [x] 日常 bug 修复
- [x] 新特性提交
- [ ] 文档改进
- [ ] 演示代码改进
- [ ] 组件样式/交互改进
- [ ] CI/CD 改进
- [ ] 重构
- [ ] 代码风格优化
- [ ] 测试用例
- [ ] 分支合并
- [ ] 其他

### 🔗 相关 Issue

<!--
1. 描述相关需求的来源，如相关的 issue 讨论链接。
-->
fix #624

### 💡 需求背景和解决方案

<!--
1. 要解决的具体问题。
2. 列出最终的 API 实现和用法。
3. 涉及UI/交互变动需要有截图或 GIF。
-->
无

### 📝 更新日志

<!--
从用户角度描述具体变化，以及可能的 breaking change 和其他风险。
-->

- break(ImageViewer): 调整 DOM
- break(ImageViewer): 属性 initialIndex 更名为 index
- feat(ImageViewer): 新增 deleteBtn 属性以及 delete 事件

- [ ] 本条 PR 不需要纳入 Changelog

### ☑️ 请求合并前的自查清单

⚠️ 请自检并全部**勾选全部选项**。⚠️

- [x] 文档已补充或无须补充
- [x] 代码演示已提供或无须提供
- [x] TypeScript 定义已补充或无须补充
- [x] Changelog 已提供或无须提供


Patch:
diff --git a/src/_common b/src/_common
index 2c821de1..ba6c01c0 160000
--- a/src/_common
+++ b/src/_common
@@ -1,1 +1,1 @@
-Subproject commit 2c821de1acae3bdb5e2ad566b8f785fdd9d32d73
+Subproject commit ba6c01c0d05fd710b4c566caaae2b613ff34edf0
diff --git a/src/image-viewer/demos/background.vue b/src/image-viewer/demos/background.vue
deleted file mode 100644
index 1acd356d..00000000
--- a/src/image-viewer/demos/background.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<template>
-  <div>
-    <t-cell-group class="dialog-type-title" title="backgroundColor: 设置遮罩的背景颜色">
-      <t-cell value-align="left">
-        <t-button theme="primary" @click="toggle"> 显示 </t-button>
-        <t-image-viewer
-          v-model="showViewer"
-          :images="images"
-          :initial-index="1"
-          :background-color="color"
-        ></t-image-viewer>
-      </t-cell>
-    </t-cell-group>
-  </div>
-</template>
-<script lang="ts">
-import { ref, defineComponent, Ref } from 'vue';
-
-export default defineComponent({
-  setup() {
-    const loading = ref(true);
-    const images: Ref<Array<string>> = ref([]);
-    const showViewer = ref(false);
-    function toggle() {
-      images.value = [
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-      ];
-      showViewer.value = !showViewer.value;
-    }
-    return { loading, images, toggle, showViewer, color: 'rgba(0, 0, 0, 1)' };
-  },
-});
-</script>
diff --git a/src/image-viewer/demos/base.vue b/src/image-viewer/demos/base.vue
index d0e0c82c..70366940 100644
--- a/src/image-viewer/demos/base.vue
+++ b/src/image-viewer/demos/base.vue
@@ -1,27 +1,14 @@
 <template>
-  <div class="image-viewer-demo">
-    <t-button block size="large" variant="outline" @click="tapShow"> 基础用法 </t-button>
-    <t-image-viewer v-model:images="images" v-model:visible="showViewer"></t-image-viewer>
-  </div>
+  <t-button block size="large" variant="outline" theme="primary" @click="visible = true">基础图片预览</t-button>
+  <t-image-viewer v-model:images="images" v-model:visible="visible" />
 </template>
+
 <script lang="ts" setup>
-import { ref, Ref } from 'vue';
+import { ref } from 'vue';
 
-const showViewer = ref(false);
-const images: Ref<Array<string>> = ref([
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-]);
-const tapShow = () => {
-  showViewer.value = true;
-};
+const visible = ref(false);
+const images = [
+  'https://tdesign.gtimg.com/miniprogram/images/swiper1.png',
+  'https://tdesign.gtimg.com/miniprogram/images/swiper2.png',
+];
 </script>
-<style lang="less" scoped>
-.image-viewer-demo {
-  margin: 0 16px;
-  button {
-    margin-bottom: 16px;
-  }
-}
-</style>
diff --git a/src/image-viewer/demos/closeBtn.vue b/src/image-viewer/demos/closeBtn.vue
deleted file mode 100644
index 3c5f84d6..00000000
--- a/src/image-viewer/demos/closeBtn.vue
+++ /dev/null
@@ -1,28 +0,0 @@
-<template>
-  <div class="image-viewer-demo">
-    <t-button block size="large" variant="outline" @click="tapShow">不展示关闭按钮</t-button>
-    <t-image-viewer v-model:images="images" v-model:visible="showViewer" :close-btn="false"></t-image-viewer>
-  </div>
-</template>
-<script lang="ts" setup>
-import { ref, Ref } from 'vue';
-
-const images: Ref<Array<string>> = ref([
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-]);
-const showViewer = ref(false);
-
-function tapShow() {
-  showViewer.value = true;
-}
-</script>
-<style lang="less" scoped>
-.image-viewer-demo {
-  margin: 0 16px;
-  button {
-    margin-bottom: 16px;
-  }
-}
-</style>
diff --git a/src/image-viewer/demos/closeEvent.vue b/src/image-viewer/demos/closeEvent.vue
deleted file mode 100644
index 191d642f..00000000
--- a/src/image-viewer/demos/closeEvent.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<template>
-  <div class="image-viewer-demo">
-    <t-button block size="large" variant="outline" @click="tapShow">监听关闭事件</t-button>
-    <t-image-viewer v-model:images="images" v-model:visible="showViewer" @close="onClose"></t-image-viewer>
-  </div>
-</template>
-<script lang="ts" setup>
-import { ref, Ref } from 'vue';
-
-const images: Ref<Array<string>> = ref([
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-  'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-]);
-const showViewer = ref(false);
-
-function tapShow() {
-  showViewer.value = true;
-}
-
-function onClose(context: { trigger: 'close-btn' | 'overlay' | 'esc'; e: MouseEvent | KeyboardEvent }) {
-  console.log('onClose: ', context);
-}
-</script>
-<style lang="less" scoped>
-.image-viewer-demo {
-  margin: 0 16px;
-  button {
-    margin-bottom: 16px;
-  }
-}
-</style>
diff --git a/src/image-viewer/demos/imageList.vue b/src/image-viewer/demos/imageList.vue
deleted file mode 100644
index f06f196b..00000000
--- a/src/image-viewer/demos/imageList.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<template>
-  <div>
-    <t-cell-group class="dialog-type-title" title="图片数组：images">
-      <t-cell value-align="left">
-        <t-button theme="primary" @click="toggle"> 图片列表 </t-button>
-        <t-image-viewer
-          v-model="showViewer"
-          v-model:images="images"
-          :initial-index="0"
-          @input="input"
-          @change="change"
-        ></t-image-viewer>
-      </t-cell>
-    </t-cell-group>
-  </div>
-</template>
-<script lang="ts">
-import { ref, defineComponent, Ref } from 'vue';
-
-export default defineComponent({
-  setup() {
-    const loading = ref(true);
-    const images: Ref<Array<string>> = ref([]);
-    const showViewer = ref(false);
-    function toggle() {
-      images.value = [
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-      ];
-      showViewer.value = !showViewer.value;
-    }
-    /** 翻页页数变化 */
-    function change(page: number) {
-      console.log(`当前页数${page}`);
-    }
-    function input() {
-      showViewer.value = false;
-    }
-    return { loading, images, toggle, showViewer, change, input };
-  },
-});
-</script>
diff --git a/src/image-viewer/demos/initialIndex.vue b/src/image-viewer/demos/initialIndex.vue
deleted file mode 100644
index 8fb41719..00000000
--- a/src/image-viewer/demos/initialIndex.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<template>
-  <div>
-    <t-cell-group class="dialog-type-title" title="initialIndex: 默认展示第二张图片">
-      <t-cell value-align="left">
-        <t-button theme="primary" @click="toggle(1)"> 默认展示 </t-button>
-        <t-image-viewer v-model="showViewer" :images="images" :initial-index="initialIndex"></t-image-viewer>
-      </t-cell>
-    </t-cell-group>
-  </div>
-</template>
-<script lang="ts">
-import { ref, defineComponent, Ref } from 'vue';
-
-export default defineComponent({
-  setup() {
-    const loading = ref(true);
-    const images: Ref<Array<string>> = ref([]);
-    const showViewer = ref(false);
-    const initialIndex = ref(0);
-    function toggle(index: number) {
-      images.value = [
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-        'https://imgcache.qq.com/open_proj/proj_qcloud_v2/rocket_images/1606728019829_yw760ok1jmpbep14i.png',
-      ];
-      showViewer.value = !showViewer.value;
-      initialIndex.value = index;
-    }
-    return { loading, images, toggle, showViewer, initialIndex };
-  },
-});
-</script>
diff --git a/src/image-viewer/demos/mobile.vue b/src/image-viewer/demos/mobile.vue
index 8880ea12..7ca24ab8 100644
--- a/src/image-viewer/demos/mobile.vue
+++ b/src/image-viewer/demos/mobile.vue
@@ -2,15 +2,22 @@
   <div class="tdesign-mobile-demo">
     <h1 class="title">ImageViewer 图片预览</h1>
     <p class="summary">图片全屏放大预览效果，包含全屏背景色、页码位置样式、增加操作等规范</p>
-    <tdesign-demo-block title="01 类型" summary="图片预览类型">
+    <tdesign-demo-block title="01 组件类型" summary="图片预览类型" padding="true">
       <BaseDemo />
-      <CloseBtnDemo />
-      <CloseEventDemo />
+    </tdesign-demo-block>
+    <tdesign-demo-block summary="带操作图片预览" padding="true">
+      <operationDemo />
     </tdesign-demo-block>
   </div>
 </template>
 <script lang="ts" setup>
 import BaseDemo from './base.vue';
-import CloseBtnDemo from './closeBtn.vue';
-import CloseEventDemo from './closeEvent.vue';
+import operationDemo from './operation.vue';
 </script>
+
+<style scoped>
+.tdesign-mobile-demo {
+  background-color: #fff;
+  min-height: 100vh;
+}
+</style>
diff --git a/src/image-viewer/demos/operation.vue b/src/image-viewer/demos/operation.vue
new file mode 100644
index 00000000..9480b9a6
--- /dev/null
+++ b/src/image-viewer/demos/operation.vue
@@ -0,0 +1,14 @@
+<template>
+  <t-button block size="large" variant="outline" theme="primary" @click="visible = true">带操作图片预览</t-button>
+  <t-image-viewer v-model:images="images" v-model:visible="visible" :delete-btn="true" show-index />
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const visible = ref(false);
+const images = [
+  'https://tdesign.gtimg.com/miniprogram/images/swiper1.png',
+  'https://tdesign.gtimg.com/miniprogram/images/swiper2.png',
+];
+</script>
diff --git a/src/image-viewer/image-viewer.en-US.md b/src/image-viewer/image-viewer.en-US.md
new file mode 100644
index 00000000..03fc1260
--- /dev/null
+++ b/src/image-viewer/image-viewer.en-US.md
@@ -0,0 +1,26 @@
+:: BASE_DOC ::
+
+## API
+### ImageViewer Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+closeBtn | Boolean / Slot / Function | true | Typescript：`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+deleteBtn | Boolean / Slot / Function | false | Typescript：`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+images | Array | [] | Typescript：`Array<string>` | N
+index | Number | - | `v-model:index` is supported | N
+defaultIndex | Number | - | uncontrolled property | N
+maxZoom | Number | 3 | Typescript：`Number` | N
+showIndex | Boolean | false | \- | N
+visible | Boolean | false | `v-model` and `v-model:visible` is supported | N
+onClose | Function |  | Typescript：`(context: { trigger: 'overlay' \| 'close-btn', visible: Boolean, index: Number }) => void`<br/> | N
+onDelete | Function |  | Typescript：`(index: Number) => void`<br/> | N
+onIndexChange | Function |  | Typescript：`(index: number, context: { trigger: 'prev' \| 'next' }) => void`<br/> | N
+
+### ImageViewer Events
+
+name | params | description
+-- | -- | --
+close | `(context: { trigger: 'overlay' \| 'close-btn', visible: Boolean, index: Number })` | \-
+delete | `(index: Number)` | \-
+index-change | `(index: number, context: { trigger: 'prev' \| 'next' })` | \-
diff --git a/src/image-viewer/image-viewer.md b/src/image-viewer/image-viewer.md
index 59f4b1ba..56dda94c 100644
--- a/src/image-viewer/image-viewer.md
+++ b/src/image-viewer/image-viewer.md
@@ -5,19 +5,22 @@
 
 名称 | 类型 | 默认值 | 说明 | 必传
 -- | -- | -- | -- | --
-closeBtn | Boolean / Slot / Function | true | 是否展示关闭按钮，值为 `true` 显示默认关闭按钮；值为 `false` 则不显示关闭按钮；也可以完全自定义关闭按钮。TS 类型：`boolean | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+closeBtn | Boolean / Slot / Function | true | 是否展示关闭按钮，值为 `true` 显示默认关闭按钮；值为 `false` 则不显示关闭按钮；也可以完全自定义关闭按钮。TS 类型：`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+deleteBtn | Boolean / Slot / Function | false | 是否显示删除操作，前提需要开启页码。TS 类型：`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 images | Array | [] | 图片数组。TS 类型：`Array<string>` | N
-initialIndex | Number | 0 | 初始化页码。TS 类型：`Number` | N
-maxZoom | Number | 3 | 最大放大比例。TS 类型：`Number` | N
+index | Number | - | 当前预览图片所在的下标。支持语法糖 `v-model:index` | N
+defaultIndex | Number | - | 当前预览图片所在的下标。非受控属性 | N
+maxZoom | Number | 3 | 【开发中】最大放大比例。TS 类型：`Number` | N
 showIndex | Boolean | false | 是否显示页码 | N
 visible | Boolean | false | 隐藏/显示预览。支持语法糖 `v-model` 或 `v-model:visible` | N
-defaultVisible | Boolean | false | 隐藏/显示预览。非受控属性 | N
-onClose | Function |  | TS 类型：`(context: { trigger: 'close-btn' | 'overlay' | 'esc'; e: MouseEvent | KeyboardEvent }) => void`<br/>关闭时触发，事件参数包含触发关闭的来源：关闭按钮、遮罩层、ESC 键 | N
-onIndexChange | Function |  | TS 类型：`(index: number, context: { trigger: 'prev' | 'next' }) => void`<br/>预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片 | N
+onClose | Function |  | TS 类型：`(context: { trigger: 'overlay' \| 'close-btn', visible: Boolean, index: Number }) => void`<br/>关闭时触发 | N
+onDelete | Function |  | TS 类型：`(index: Number) => void`<br/>点击删除操作按钮时触发 | N
+onIndexChange | Function |  | TS 类型：`(index: number, context: { trigger: 'prev' \| 'next' }) => void`<br/>预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片 | N
 
 ### ImageViewer Events
 
 名称 | 参数 | 描述
 -- | -- | --
-close | `(context: { trigger: 'close-btn' | 'overlay' | 'esc'; e: MouseEvent | KeyboardEvent })` | 关闭时触发，事件参数包含触发关闭的来源：关闭按钮、遮罩层、ESC 键
-index-change | `(index: number, context: { trigger: 'prev' | 'next' })` | 预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片
+close | `(context: { trigger: 'overlay' \| 'close-btn', visible: Boolean, index: Number })` | 关闭时触发
+delete | `(index: Number)` | 点击删除操作按钮时触发
+index-change | `(index: number, context: { trigger: 'prev' \| 'next' })` | 预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片
diff --git a/src/image-viewer/image-viewer.vue b/src/image-viewer/image-viewer.vue
index 7d642f0a..3bf15348 100644
--- a/src/image-viewer/image-viewer.vue
+++ b/src/image-viewer/image-viewer.vue
@@ -1,91 +1,91 @@
 <template>
-  <t-overlay :class="`${prefix}-image-viewer`" :visible="visible">
-    <template v-if="lazyVisible">
-      <div :class="`${name}__close-icon`" @click="handleClose($event, 'close-btn')">
-        <t-node v-if="!(typeof closeBtnTNode === 'boolean')" :content="closeBtnTNode"></t-node>
-        <close-circle-filled-icon v-else-if="typeof closeBtn === 'boolean' && closeBtn" />
+  <transition name="fade">
+    <div v-if="visible" :class="`${prefix}-image-viewer`">
+      <div :class="`${name}__mask`" @click="handleClose($event, 'overlay')" />
+      <div :class="`${name}__nav`">
+        <div v-if="closeNode" :class="`${name}__nav-close`" @click="handleClose($event, 'close-btn')">
+          <t-node :content="closeNode" />
+        </div>
+
+        <div v-if="showIndex" :class="`${name}__nav-index`">{{ (currentIndex ?? 0) + 1 }}/{{ images?.length }}</div>
+
+        <div v-if="deleteNode" :class="`${name}__nav-delete`" @click="handleDelete">
+          <t-node :content="deleteNode" />
+        </div>
       </div>
-      <t-swiper
-        :autoplay="false"
-        :class="`${name}__swipe`"
-        :default-current="initialIndex"
-        :navigation="navigation"
-        :on-change="onSwiperChange"
-      >
+      <t-swiper :autoplay="false" :class="`${name}__content`" :current="currentIndex" @change="onSwiperChange">
         <t-swiper-item
           v-for="(image, index) in images"
-          :key="image + index"
-          :class="`${name}__swipe-item`"
+          :key="index"
+          :class="`${name}__swiper-item`"
           @touchstart="onTouchStart"
           @touchmove="onTouchMove"
           @touchend="onTouchEnd"
         >
-          <img :src="image" :style="imageStyle" :class="`${name}__image`" />
+          <t-image :src="image" :style="imageStyle" />
         </t-swiper-item>
       </t-swiper>
-    </template>
-  </t-overlay>
+    </div>
+  </transition>
 </template>
 
 <script lang="ts">
-import { computed, toRefs, ref, defineComponent, reactive, watch, getCurrentInstance, CSSProperties } from 'vue';
-import { CloseCircleFilledIcon } from 'tdesign-icons-vue-next';
+import { computed, defineComponent, reactive, getCurrentInstance, CSSProperties, h, Transition } from 'vue';
+import { CloseIcon, DeleteIcon } from 'tdesign-icons-vue-next';
+
 import config from '../config';
-import ImageViewerProps from './props';
+import ImagediverProps from './props';
 import { renderTNode, TNode, useEmitEvent, useDefault, useTouch } from '../shared';
 import { TdImageViewerProps } from './type';
-import { Swiper as TSwiper, SwiperItem as TSwiperItem, SwiperNavigation } from '../swiper';
-import TOverlay from '../overlay';
 
-export type TriggerType = 'close-btn' | 'overlay' | 'esc';
+// inner components
+import { Swiper as TSwiper, SwiperItem as TSwiperItem } from '../swiper';
+import TImage from '../image';
+
 const { prefix } = config;
 const name = `${prefix}-image-viewer`;
 
-/*
-initialIndex, 因 swiper 不支持 defaultCurrent
-
-
-onIndexChange, 因 swiper 未提供 'prev' | 'next'， 所以没有 context
-*/
 const getDistance = (touches: TouchList) =>
   Math.sqrt((touches[0].clientX - touches[1].clientX) ** 2 + (touches[0].clientY - touches[1].clientY) ** 2);
 
 export default defineComponent({
   name,
   components: {
-    CloseCircleFilledIcon,
+    Transition,
     TSwiper,
     TSwiperItem,
-    TOverlay,
     TNode,
+    TImage,
   },
-  props: ImageViewerProps,
+  props: ImagediverProps,
   emits: ['close', 'index-change', 'update:visible', 'update:modelValue', 'change'],
   setup(props, context) {
+    const internalInstance = getCurrentInstance();
     const state = reactive({
       zooming: false,
       scale: 1,
     });
     const emitEvent = useEmitEvent(props, context.emit);
-    const [visible, setVisible] = useDefault<TdImageViewerProps['visible'], TdImageViewerProps>(
+    const [visible, setVisible] = useDefault(props, context.emit, 'visible', 'change');
+    const [currentIndex, setIndex] = useDefault<TdImageViewerProps['index'], TdImageViewerProps>(
       props,
       context.emit,
-      'visible',
-      'change',
+      'index',
+      'index-change',
     );
-    // 因 Overlay 未提供lazy属性，先暂时自行实现
-    const lazyVisible = ref(visible.value);
     const touch = useTouch();
-    const internalInstance = getCurrentInstance();
-    const closeBtnTNode = computed(() => {
-      return renderTNode(internalInstance, 'closeBtn');
-    });
-    const navigation = computed<SwiperNavigation>(() => {
-      if (props.showIndex) {
-        return { type: 'fraction' };
-      }
-      return { type: 'dots', showSlideBtn: false };
-    });
+
+    // node
+    const closeNode = computed(() =>
+      renderTNode(internalInstance, 'close-btn', {
+        defaultNode: h(CloseIcon),
+      }),
+    );
+    const deleteNode = computed(() =>
+      renderTNode(internalInstance, 'delete-btn', {
+        defaultNode: h(DeleteIcon),
+      }),
+    );
 
     const imageStyle = computed(() => {
       const { scale, zooming } = state;
@@ -100,13 +100,17 @@ export default defineComponent({
       return style;
     });
 
-    const handleClose = (e: Event, trigger: TriggerType) => {
+    const handleClose = (e: Event, trigger: string) => {
       setVisible(false);
       emitEvent('close', { trigger, e });
     };
 
+    const handleDelete = () => {
+      emitEvent('delete', currentIndex);
+    };
+
     const onSwiperChange = (index: number, context: any) => {
-      emitEvent('index-change', index);
+      setIndex(index, { context });
     };
 
     let fingerNum: number;
@@ -213,27 +217,16 @@ export default defineComponent({
       touch.reset();
     };
 
-    watch(
-      () => visible.value,
-      (value) => {
-        if (!value) {
-          resetScale();
-        }
-        setTimeout(() => {
-          lazyVisible.value = value;
-        }, 300);
-      },
-    );
     return {
       name,
       prefix,
-      closeBtnTNode,
-      navigation,
+      closeNode,
+      deleteNode,
+      currentIndex,
       imageStyle,
-      lazyVisible,
-      ...toRefs(props),
       visible,
       handleClose,
+      handleDelete,
       onSwiperChange,
       onTouchStart,
       onTouchMove,
diff --git a/src/image-viewer/props.ts b/src/image-viewer/props.ts
index 7166cf2e..0641a9f4 100644
--- a/src/image-viewer/props.ts
+++ b/src/image-viewer/props.ts
@@ -13,17 +13,26 @@ export default {
     type: [Boolean, Function] as PropType<TdImageViewerProps['closeBtn']>,
     default: true,
   },
+  /** 是否显示删除操作，前提需要开启页码 */
+  deleteBtn: {
+    type: [Boolean, Function] as PropType<TdImageViewerProps['deleteBtn']>,
+    default: false,
+  },
   /** 图片数组 */
   images: {
     type: Array as PropType<TdImageViewerProps['images']>,
     default: (): TdImageViewerProps['images'] => [],
   },
-  /** 初始化页码 */
-  initialIndex: {
+  /** 当前预览图片所在的下标 */
+  index: {
+    type: Number,
+    default: undefined,
+  },
+  /** 当前预览图片所在的下标，非受控属性 */
+  defaultIndex: {
     type: Number,
-    default: 0,
   },
-  /** 最大放大比例 */
+  /** 【开发中】最大放大比例 */
   maxZoom: {
     type: Number,
     default: 3,
@@ -41,8 +50,10 @@ export default {
   },
   /** 隐藏/显示预览，非受控属性 */
   defaultVisible: Boolean,
-  /** 关闭时触发，事件参数包含触发关闭的来源：关闭按钮、遮罩层、ESC 键 */
+  /** 关闭时触发 */
   onClose: Function as PropType<TdImageViewerProps['onClose']>,
+  /** 点击删除操作按钮时触发 */
+  onDelete: Function as PropType<TdImageViewerProps['onDelete']>,
   /** 预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片 */
   onIndexChange: Function as PropType<TdImageViewerProps['onIndexChange']>,
 };
diff --git a/src/image-viewer/style/index.js b/src/image-viewer/style/index.js
index b9e0f3db..d9a515bf 100644
--- a/src/image-viewer/style/index.js
+++ b/src/image-viewer/style/index.js
@@ -1,1 +1,1 @@
-import '../../_common/style/mobile/components/image-viewer/_index.less';
+import '../../_common/style/mobile/components/image-viewer/v2/_index.less';
diff --git a/src/image-viewer/type.ts b/src/image-viewer/type.ts
index 10131eea..f287667a 100644
--- a/src/image-viewer/type.ts
+++ b/src/image-viewer/type.ts
@@ -12,18 +12,26 @@ export interface TdImageViewerProps {
    * @default true
    */
   closeBtn?: boolean | TNode;
+  /**
+   * 是否显示删除操作，前提需要开启页码
+   * @default false
+   */
+  deleteBtn?: boolean | TNode;
   /**
    * 图片数组
    * @default []
    */
   images?: Array<string>;
   /**
-   * 初始化页码
-   * @default 0
+   * 当前预览图片所在的下标
    */
-  initialIndex?: Number;
+  index?: number;
   /**
-   * 最大放大比例
+   * 当前预览图片所在的下标，非受控属性
+   */
+  defaultIndex?: number;
+  /**
+   * 【开发中】最大放大比例
    * @default 3
    */
   maxZoom?: Number;
@@ -48,9 +56,13 @@ export interface TdImageViewerProps {
    */
   modelValue?: boolean;
   /**
-   * 关闭时触发，事件参数包含触发关闭的来源：关闭按钮、遮罩层、ESC 键
+   * 关闭时触发
+   */
+  onClose?: (context: { trigger: 'overlay' | 'close-btn'; visible: Boolean; index: Number }) => void;
+  /**
+   * 点击删除操作按钮时触发
    */
-  onClose?: (context: { trigger: 'close-btn' | 'overlay' | 'esc'; e: MouseEvent | KeyboardEvent }) => void;
+  onDelete?: (index: Number) => void;
   /**
    * 预览图片切换时触发，`context.prev` 切换到上一张图片，`context.next` 切换到下一张图片
    */


Test patch:
diff --git a/src/form/__test__/__snapshots__/demo.test.jsx.snap b/src/form/__test__/__snapshots__/demo.test.jsx.snap
index 64ec9d60..780b9fa0 100644
--- a/src/form/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/form/__test__/__snapshots__/demo.test.jsx.snap
@@ -1423,13 +1423,7 @@ exports[`Form > Form horizontalVue demo works fine 1`] = `
               multiple=""
               type="file"
             />
-            <div
-              class="t-overlay t-image-viewer"
-              style="z-index: 1000; transition-duration: 300ms; display: none;"
-            >
-              
-              
-            </div>
+            <!--v-if-->
           </div>
           
         </div>
@@ -3036,13 +3030,7 @@ exports[`Form > Form mobileVue demo works fine 1`] = `
                     multiple=""
                     type="file"
                   />
-                  <div
-                    class="t-overlay t-image-viewer"
-                    style="z-index: 1000; transition-duration: 300ms; display: none;"
-                  >
-                    
-                    
-                  </div>
+                  <!--v-if-->
                 </div>
                 
               </div>
@@ -4514,13 +4502,7 @@ exports[`Form > Form verticalVue demo works fine 1`] = `
               multiple=""
               type="file"
             />
-            <div
-              class="t-overlay t-image-viewer"
-              style="z-index: 1000; transition-duration: 300ms; display: none;"
-            >
-              
-              
-            </div>
+            <!--v-if-->
           </div>
           
         </div>
diff --git a/src/image-viewer/__test__/__snapshots__/demo.test.jsx.snap b/src/image-viewer/__test__/__snapshots__/demo.test.jsx.snap
index 3d3e2c44..1ef41c3e 100644
--- a/src/image-viewer/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/image-viewer/__test__/__snapshots__/demo.test.jsx.snap
@@ -1,140 +1,13 @@
 // Vitest Snapshot v1
 
-exports[`ImageViewer > ImageViewer backgroundVue demo works fine 1`] = `
-<div>
-  <div
-    class="t-cell-group t-cell-group--default dialog-type-title"
-  >
-    <div
-      class="t-cell-group__title"
-    >
-      
-      backgroundColor: 设置遮罩的背景颜色
-      
-    </div>
-    
-    <div
-      class="t-cell t-cell--middle"
-      value-align="left"
-    >
-      <div
-        class="t-cell__left"
-      >
-        <!--v-if-->
-        <!--v-if-->
-      </div>
-      <!--v-if-->
-      <div
-        class="t-cell__note"
-      >
-        
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-medium t-button--base t-button--primary t-button--rectangle"
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-             显示 
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          style="z-index: 1000; transition-duration: 300ms; background-color: rgb(0, 0, 0); display: none;"
-        >
-          
-          
-        </div>
-        
-      </div>
-      <!--v-if-->
-    </div>
-    
-  </div>
-</div>
-`;
-
 exports[`ImageViewer > ImageViewer baseVue demo works fine 1`] = `
 <div
-  class="image-viewer-demo"
-  data-v-734c791c=""
->
-  <button
-    aria-disabled="false"
-    class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-    data-v-734c791c=""
-    role="button"
-    type="button"
-  >
-    <!---->
-    <span
-      class="t-button__content"
-    >
-      
-       基础用法 
-      
-    </span>
-    <!---->
-  </button>
-  <div
-    class="t-overlay t-image-viewer"
-    data-v-734c791c=""
-    style="z-index: 1000; transition-duration: 300ms; display: none;"
-  >
-    
-    
-  </div>
-</div>
-`;
-
-exports[`ImageViewer > ImageViewer closeBtnVue demo works fine 1`] = `
-<div
-  class="image-viewer-demo"
-  data-v-04bcb836=""
->
-  <button
-    aria-disabled="false"
-    class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-    data-v-04bcb836=""
-    role="button"
-    type="button"
-  >
-    <!---->
-    <span
-      class="t-button__content"
-    >
-      
-      不展示关闭按钮
-      
-    </span>
-    <!---->
-  </button>
-  <div
-    class="t-overlay t-image-viewer"
-    data-v-04bcb836=""
-    style="z-index: 1000; transition-duration: 300ms; display: none;"
-  >
-    
-    
-  </div>
-</div>
-`;
-
-exports[`ImageViewer > ImageViewer closeEventVue demo works fine 1`] = `
-<div
-  class="image-viewer-demo"
-  data-v-3939d0e3=""
+  data-v-app=""
 >
+  
   <button
     aria-disabled="false"
-    class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-    data-v-3939d0e3=""
+    class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle t-button--block"
     role="button"
     type="button"
   >
@@ -143,158 +16,36 @@ exports[`ImageViewer > ImageViewer closeEventVue demo works fine 1`] = `
       class="t-button__content"
     >
       
-      监听关闭事件
+      基础图片预览
       
     </span>
     <!---->
   </button>
-  <div
-    class="t-overlay t-image-viewer"
-    data-v-3939d0e3=""
-    style="z-index: 1000; transition-duration: 300ms; display: none;"
-  >
-    
-    
-  </div>
-</div>
-`;
-
-exports[`ImageViewer > ImageViewer imageListVue demo works fine 1`] = `
-<div>
-  <div
-    class="t-cell-group t-cell-group--default dialog-type-title"
-  >
-    <div
-      class="t-cell-group__title"
-    >
-      
-      图片数组：images
-      
-    </div>
-    
-    <div
-      class="t-cell t-cell--middle"
-      value-align="left"
-    >
-      <div
-        class="t-cell__left"
-      >
-        <!--v-if-->
-        <!--v-if-->
-      </div>
-      <!--v-if-->
-      <div
-        class="t-cell__note"
-      >
-        
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-medium t-button--base t-button--primary t-button--rectangle"
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-             图片列表 
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          style="z-index: 1000; transition-duration: 300ms; display: none;"
-        >
-          
-          
-        </div>
-        
-      </div>
-      <!--v-if-->
-    </div>
-    
-  </div>
-</div>
-`;
-
-exports[`ImageViewer > ImageViewer initialIndexVue demo works fine 1`] = `
-<div>
-  <div
-    class="t-cell-group t-cell-group--default dialog-type-title"
-  >
-    <div
-      class="t-cell-group__title"
-    >
-      
-      initialIndex: 默认展示第二张图片
-      
-    </div>
-    
-    <div
-      class="t-cell t-cell--middle"
-      value-align="left"
-    >
-      <div
-        class="t-cell__left"
-      >
-        <!--v-if-->
-        <!--v-if-->
-      </div>
-      <!--v-if-->
-      <div
-        class="t-cell__note"
-      >
-        
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-medium t-button--base t-button--primary t-button--rectangle"
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-             默认展示 
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          style="z-index: 1000; transition-duration: 300ms; display: none;"
-        >
-          
-          
-        </div>
-        
-      </div>
-      <!--v-if-->
-    </div>
-    
-  </div>
+  <!--v-if-->
+  
 </div>
 `;
 
 exports[`ImageViewer > ImageViewer mobileVue demo works fine 1`] = `
 <div
   class="tdesign-mobile-demo"
+  data-v-ef8302fa=""
 >
   <h1
     class="title"
+    data-v-ef8302fa=""
   >
     ImageViewer 图片预览
   </h1>
   <p
     class="summary"
+    data-v-ef8302fa=""
   >
     图片全屏放大预览效果，包含全屏背景色、页码位置样式、增加操作等规范
   </p>
   <div
     class="tdesign-mobile-demo-block"
+    data-v-ef8302fa=""
   >
     <div
       class="tdesign-mobile-demo-block__header"
@@ -302,7 +53,7 @@ exports[`ImageViewer > ImageViewer mobileVue demo works fine 1`] = `
       <h2
         class="tdesign-mobile-demo-block__title"
       >
-        01 类型
+        01 组件类型
       </h2>
       <p
         class="tdesign-mobile-demo-block__summary"
@@ -311,101 +62,96 @@ exports[`ImageViewer > ImageViewer mobileVue demo works fine 1`] = `
       </p>
     </div>
     <div
-      class="tdesign-mobile-demo-block__slot"
+      class="tdesign-mobile-demo-block__slot with-padding"
     >
       
-      <div
-        class="image-viewer-demo"
-        data-v-734c791c=""
+      
+      <button
+        aria-disabled="false"
+        class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle t-button--block"
+        role="button"
+        type="button"
       >
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-          data-v-734c791c=""
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-             基础用法 
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          data-v-734c791c=""
-          style="z-index: 1000; transition-duration: 300ms; display: none;"
+        <!---->
+        <span
+          class="t-button__content"
         >
           
+          基础图片预览
           
-        </div>
-      </div>
-      <div
-        class="image-viewer-demo"
-        data-v-04bcb836=""
+        </span>
+        <!---->
+      </button>
+      <!--v-if-->
+      
+      
+    </div>
+  </div>
+  <div
+    class="tdesign-mobile-demo-block tdesign-mobile-demo-block_notitle"
+    data-v-ef8302fa=""
+  >
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <!--v-if-->
+      <p
+        class="tdesign-mobile-demo-block__summary tdesign-mobile-demo-block_subtitle"
       >
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-          data-v-04bcb836=""
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-            不展示关闭按钮
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          data-v-04bcb836=""
-          style="z-index: 1000; transition-duration: 300ms; display: none;"
-        >
-          
-          
-        </div>
-      </div>
-      <div
-        class="image-viewer-demo"
-        data-v-3939d0e3=""
+        带操作图片预览
+      </p>
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot with-padding"
+    >
+      
+      
+      <button
+        aria-disabled="false"
+        class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle t-button--block"
+        role="button"
+        type="button"
       >
-        <button
-          aria-disabled="false"
-          class="t-button t-button--size-large t-button--outline t-button--default t-button--rectangle t-button--block"
-          data-v-3939d0e3=""
-          role="button"
-          type="button"
-        >
-          <!---->
-          <span
-            class="t-button__content"
-          >
-            
-            监听关闭事件
-            
-          </span>
-          <!---->
-        </button>
-        <div
-          class="t-overlay t-image-viewer"
-          data-v-3939d0e3=""
-          style="z-index: 1000; transition-duration: 300ms; display: none;"
+        <!---->
+        <span
+          class="t-button__content"
         >
           
+          带操作图片预览
           
-        </div>
-      </div>
+        </span>
+        <!---->
+      </button>
+      <!--v-if-->
+      
       
     </div>
   </div>
 </div>
 `;
+
+exports[`ImageViewer > ImageViewer operationVue demo works fine 1`] = `
+<div
+  data-v-app=""
+>
+  
+  <button
+    aria-disabled="false"
+    class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle t-button--block"
+    role="button"
+    type="button"
+  >
+    <!---->
+    <span
+      class="t-button__content"
+    >
+      
+      带操作图片预览
+      
+    </span>
+    <!---->
+  </button>
+  <!--v-if-->
+  
+</div>
+`;
diff --git a/src/image-viewer/__test__/demo.test.jsx b/src/image-viewer/__test__/demo.test.jsx
index d36ccaf3..05f039a0 100644
--- a/src/image-viewer/__test__/demo.test.jsx
+++ b/src/image-viewer/__test__/demo.test.jsx
@@ -3,22 +3,14 @@
  */
 
 import { mount } from '@vue/test-utils';
-import backgroundVue from '@/image-viewer/demos/background.vue';
 import baseVue from '@/image-viewer/demos/base.vue';
-import closeBtnVue from '@/image-viewer/demos/closeBtn.vue';
-import closeEventVue from '@/image-viewer/demos/closeEvent.vue';
-import imageListVue from '@/image-viewer/demos/imageList.vue';
-import initialIndexVue from '@/image-viewer/demos/initialIndex.vue';
 import mobileVue from '@/image-viewer/demos/mobile.vue';
+import operationVue from '@/image-viewer/demos/operation.vue';
 
 const mapper = {
-  backgroundVue,
   baseVue,
-  closeBtnVue,
-  closeEventVue,
-  imageListVue,
-  initialIndexVue,
   mobileVue,
+  operationVue,
 };
 
 describe('ImageViewer', () => {
diff --git a/src/image-viewer/__test__/index.test.jsx b/src/image-viewer/__test__/index.test.jsx
index 3d105cb2..063ace6b 100644
--- a/src/image-viewer/__test__/index.test.jsx
+++ b/src/image-viewer/__test__/index.test.jsx
@@ -1,6 +1,6 @@
 import { nextTick, ref } from 'vue';
 import { mount } from '@vue/test-utils';
-import { CloseCircleFilledIcon, AddCircleIcon } from 'tdesign-icons-vue-next';
+import { AddCircleIcon } from 'tdesign-icons-vue-next';
 import { describe, it, vi } from 'vitest';
 import ImageViewer from '../image-viewer.vue';
 import { Swiper } from '../../swiper';
@@ -14,13 +14,13 @@ const images = ref([
 
 describe('ImageViewer', () => {
   describe('props', () => {
-    it(': closeBtn', async () => {
+    it(':closeBtn', async () => {
       const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} closeBtn={false} />);
 
-      expect(wrapper.findComponent(CloseCircleFilledIcon).exists()).toBe(false);
+      expect(wrapper.find('.t-image-viewer__nav-close').exists()).toBe(false);
     });
 
-    it(': images', async () => {
+    it(':images', async () => {
       const emptyImages = mount(<ImageViewer visible={true} />);
       expect(emptyImages.find('.t-swiper-item').exists()).toBe(false);
 
@@ -34,7 +34,7 @@ describe('ImageViewer', () => {
       expect(wrapper.findAll('.t-swiper-item').length - 2).toBe(images.value.length);
     });
 
-    it(': maxZoom', async () => {
+    it(':maxZoom', async () => {
       const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} maxZoom={2} />);
 
       const target = wrapper.find('.t-swiper-item');
@@ -57,13 +57,7 @@ describe('ImageViewer', () => {
       trigger(target, 'touchend', 50, 50);
     });
 
-    it(': showIndex', async () => {
-      const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} showIndex={true} />);
-
-      expect(wrapper.find('.t-swiper__pagination-fraction').exists()).toBe(true);
-    });
-
-    it(': visible', async () => {
+    it(':visible', async () => {
       const visible = ref(false);
       const wrapper = mount(<ImageViewer v-model:images={images.value} v-model:visible={visible.value} />);
 
@@ -73,7 +67,7 @@ describe('ImageViewer', () => {
   });
 
   describe('slots', () => {
-    it(': closeBtn', () => {
+    it(':closeBtn', () => {
       const wrapper = mount(
         <ImageViewer v-model:images={images.value} visible={true} closeBtn={() => <AddCircleIcon />} />,
       );
@@ -83,38 +77,11 @@ describe('ImageViewer', () => {
   });
 
   describe('event', () => {
-    it(': close', async () => {
+    it(':close', async () => {
       const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} />);
 
-      await wrapper.findComponent(CloseCircleFilledIcon).trigger('click');
+      await wrapper.find('.t-image-viewer__nav-close').trigger('click');
       expect(wrapper.emitted()).toHaveProperty('close');
     });
   });
-
-  describe('function', () => {
-    it(': onClose', async () => {
-      const onClose = vi.fn();
-
-      const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} onClose={onClose} />);
-
-      await wrapper.findComponent(CloseCircleFilledIcon).trigger('click');
-      expect(onClose).toHaveBeenCalled();
-    });
-
-    // it(': onIndexChange', async () => {
-    //   const onIndexChange = vi.fn();
-
-    //   const wrapper = mount(<ImageViewer v-model:images={images.value} visible={true} onIndexChange={onIndexChange} />);
-
-    //   const target = wrapper.find('.t-swiper__container');
-
-    //   await trigger(target, 'touchstart', 0, 0);
-    //   await trigger(target, 'touchmove', 30, 0);
-    //   await trigger(target, 'touchmove', 60, 0);
-    //   await trigger(target, 'touchmove', 120, 0);
-    //   await trigger(target, 'touchend', 120, 0);
-
-    //   expect(wrapper.element).toMatchSnapshot();
-    // });
-  });
 });
diff --git a/src/upload/__test__/__snapshots__/demo.test.jsx.snap b/src/upload/__test__/__snapshots__/demo.test.jsx.snap
index d78f72db..8363e7d4 100644
--- a/src/upload/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/upload/__test__/__snapshots__/demo.test.jsx.snap
@@ -41,13 +41,7 @@ exports[`Upload > Upload baseVue demo works fine 1`] = `
       hidden=""
       type="file"
     />
-    <div
-      class="t-overlay t-image-viewer"
-      style="z-index: 1000; transition-duration: 300ms; display: none;"
-    >
-      
-      
-    </div>
+    <!--v-if-->
   </div>
 </div>
 `;
@@ -127,13 +121,7 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
             hidden=""
             type="file"
           />
-          <div
-            class="t-overlay t-image-viewer"
-            style="z-index: 1000; transition-duration: 300ms; display: none;"
-          >
-            
-            
-          </div>
+          <!--v-if-->
         </div>
       </div>
       
@@ -381,13 +369,7 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
             multiple=""
             type="file"
           />
-          <div
-            class="t-overlay t-image-viewer"
-            style="z-index: 1000; transition-duration: 300ms; display: none;"
-          >
-            
-            
-          </div>
+          <!--v-if-->
         </div>
       </div>
       
@@ -633,13 +615,7 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
             hidden=""
             type="file"
           />
-          <div
-            class="t-overlay t-image-viewer"
-            style="z-index: 1000; transition-duration: 300ms; display: none;"
-          >
-            
-            
-          </div>
+          <!--v-if-->
         </div>
       </div>
       <div
@@ -779,13 +755,7 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
             hidden=""
             type="file"
           />
-          <div
-            class="t-overlay t-image-viewer"
-            style="z-index: 1000; transition-duration: 300ms; display: none;"
-          >
-            
-            
-          </div>
+          <!--v-if-->
         </div>
       </div>
       
@@ -1021,13 +991,7 @@ exports[`Upload > Upload multipleVue demo works fine 1`] = `
       multiple=""
       type="file"
     />
-    <div
-      class="t-overlay t-image-viewer"
-      style="z-index: 1000; transition-duration: 300ms; display: none;"
-    >
-      
-      
-    </div>
+    <!--v-if-->
   </div>
 </div>
 `;
@@ -1255,13 +1219,7 @@ exports[`Upload > Upload statusVue demo works fine 1`] = `
         hidden=""
         type="file"
       />
-      <div
-        class="t-overlay t-image-viewer"
-        style="z-index: 1000; transition-duration: 300ms; display: none;"
-      >
-        
-        
-      </div>
+      <!--v-if-->
     </div>
   </div>
   <div
@@ -1401,13 +1359,7 @@ exports[`Upload > Upload statusVue demo works fine 1`] = `
         hidden=""
         type="file"
       />
-      <div
-        class="t-overlay t-image-viewer"
-        style="z-index: 1000; transition-duration: 300ms; display: none;"
-      >
-        
-        
-      </div>
+      <!--v-if-->
     </div>
   </div>