Repository: Tencent/tdesign-mobile-vue
Pull request #586 (2023-04-13 12:00:13)

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


github-actions[bot]: <a href="https://preview-pr586-tdesign-mobile-vue.surge.sh"><img height="96" alt="完成" src="https://user-images.githubusercontent.com/15634204/150816437-9f5bb788-cd67-4cbc-9897-b82d74e9aa65.png" /></a>
<!-- [工作流地址](https://github.com/Tencent/tdesign-mobile-vue/actions/runs/4697145883) -->
<!-- AUTO_PREVIEW_HOOK -->

Patch:
diff --git a/src/_common b/src/_common
index 1c0f362b..426b495c 160000
--- a/src/_common
+++ b/src/_common
@@ -1,1 +1,1 @@
-Subproject commit 1c0f362b9aceb3c9edd2156580187fa6ca18c751
+Subproject commit 426b495c6016c93d6ac1695c9cf00f44e1f71314
diff --git a/src/message/demos/base.vue b/src/message/demos/base.vue
index 11503e22..d5cd9df8 100644
--- a/src/message/demos/base.vue
+++ b/src/message/demos/base.vue
@@ -1,56 +1,64 @@
 <template>
   <div class="button-demo" style="margin: 0 16px">
-    <t-button block size="large" variant="outline" @click="showTextMessage">纯文字通知</t-button>
-    <t-button block size="large" variant="outline" @click="showIconMessage">带图标通知</t-button>
-    <t-button block size="large" variant="outline" @click="showCloseMessage">带关闭通知</t-button>
-    <t-button block size="large" variant="outline" @click="showScrollMessage">滚动通知</t-button>
-    <t-button block size="large" variant="outline" @click="showBtnMessage">带按钮通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showTextMessage">纯文字的通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showIconMessage">带图标的通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showCloseMessage">带关闭的通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showScrollMessage">可滚动的通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showBtnMessage">带按钮的通知</t-button>
   </div>
 
   <!-- 纯文字通知 -->
-  <t-message v-model="visible" :icon="false" :offset="[20, 32]" :duration="5000"
-    >这是一条纯文字的消息通知 5s消失
-  </t-message>
+  <t-message v-model="visible" :icon="false" :offset="[10, 16]" :duration="5000" content="这是一条普通的通知信息" />
 
   <!-- 带图标通知 -->
-  <t-message v-model="visible1" :offset="['20px', '32px']" :duration="5000" content="这是一条带图标的消息通知 5s消失">
-  </t-message>
+  <t-message
+    v-model="visible1"
+    :icon="prefixIcon"
+    :offset="['10px', '16px']"
+    :duration="5000"
+    content="这是一条普通的通知信息"
+  />
 
   <!-- 带关闭通知 -->
   <t-message
     v-model="visible2"
-    :offset="['20px', 32]"
-    :close-btn="true"
+    :icon="prefixIcon"
+    :offset="['10px', 16]"
     :duration="-1"
-    content="这是一条带关闭的消息通知，常驻可关闭"
-  ></t-message>
+    content="这是一条普通的通知信息"
+  >
+    <template #closeBtn>
+      <t-button class="close-btn" variant="text">按钮</t-button>
+      <closeIcon class="t-message__icon--right" />
+    </template>
+  </t-message>
 
   <!-- 滚动通知 -->
   <t-message
     v-model="visible3"
-    :offset="[20, 32]"
-    :marquee="{ speed: 50, loop: -1, delay: 5000 }"
-    :duration="-1"
-    content="这是一条 5s后开始滚动的通知信息"
-  ></t-message>
+    :icon="false"
+    :offset="[10, 16]"
+    :marquee="true"
+    content="这是一条普通的通知信息，这是一条普通的通知信息，这是一条普通的通知信息"
+  />
 
   <!-- 带按钮通知 -->
   <t-message
     v-model="visible4"
-    :icon="iconContent"
-    :offset="[20, 32]"
+    :icon="notificationIcon"
+    :offset="[10, 16]"
     :duration="-1"
-    content="这是一条带操作的消息通知"
+    content="这是一条普通的通知信息"
   >
     <template #closeBtn>
-      <t-button class="close-btn" theme="primary" variant="outline" size="small" shape="round">按钮</t-button>
+      <t-button class="close-btn" variant="text">按钮</t-button>
     </template>
   </t-message>
 </template>
 
 <script lang="ts" setup>
 import { h, ref } from 'vue';
-import { NotificationIcon } from 'tdesign-icons-vue-next';
+import { ErrorCircleFilledIcon, CloseIcon, NotificationFilledIcon } from 'tdesign-icons-vue-next';
 
 const visible = ref(false);
 const visible1 = ref(false);
@@ -58,39 +66,74 @@ const visible2 = ref(false);
 const visible3 = ref(false);
 const visible4 = ref(false);
 
-const iconContent = () => h(NotificationIcon);
+const suffixIconStyle = {
+  color: 'rgba(0, 0, 0, 0.4)',
+  cursor: 'pointer',
+};
+
+const prefixIcon = () => h(ErrorCircleFilledIcon, { color: '#0052D9' });
+const notificationIcon = () => h(NotificationFilledIcon, { color: '#0052D9' });
+const closeIcon = () => h(CloseIcon, { ...suffixIconStyle });
 
 const showTextMessage = () => {
+  cleanMessage();
   visible.value = true;
 };
 
 const showIconMessage = () => {
+  cleanMessage();
   visible1.value = true;
 };
 
 const showCloseMessage = () => {
+  cleanMessage();
   visible2.value = true;
 };
 const showScrollMessage = () => {
+  cleanMessage();
   visible3.value = true;
 };
 
 const showBtnMessage = () => {
+  cleanMessage();
   visible4.value = true;
 };
+
+const cleanMessage = () => {
+  visible.value = false;
+  visible1.value = false;
+  visible2.value = false;
+  visible3.value = false;
+  visible4.value = false;
+};
+</script>
+
+<script lang="ts">
+export default {
+  name: 'BaseDemo',
+};
 </script>
 
 <style lang="less" scoped>
+.tdesign-mobile-demo-block .button-demo {
+  .t-button {
+    border-radius: 6px;
+    &.t-size-l {
+      height: 48px;
+      font-size: 16px;
+      font-weight: bold;
+    }
+  }
+}
+
 .close-btn {
   margin-left: 8px;
-  font-size: inherit;
-  line-height: inherit;
   height: 22px;
   line-height: 22px;
-  border-radius: 4px;
-  border-color: inherit;
-  color: inherit;
-  min-height: 0;
-  background: transparent;
+  color: #0052d9;
+
+  &:active {
+    background: none;
+  }
 }
 </style>
diff --git a/src/message/demos/mobile.vue b/src/message/demos/mobile.vue
index 77d9c352..fa6ca602 100644
--- a/src/message/demos/mobile.vue
+++ b/src/message/demos/mobile.vue
@@ -1,13 +1,12 @@
 <template>
   <div class="tdesign-mobile-demo">
     <h1 class="title">Message 消息通知</h1>
-    <p class="summary">用于页面消息通知提示，具有成功提示、提醒、警示等功能，通常在顶部出现，可以自动消失或点击关闭</p>
-    <tdesign-demo-block title="01 类型" summary="弹窗内容为存文本、标题和副标题、带输入框">
-      <!-- <functionDemo /> -->
+    <p class="summary" style="margin: 8px 16px 0">用于轻量级反馈或提示，不会打断用户操作。</p>
+    <tdesign-demo-block title="01 组件类型" summary="消息通知内容为文本、带操作按钮">
       <baseDemo />
     </tdesign-demo-block>
 
-    <tdesign-demo-block title="02 状态" summary="弹窗内容为存文本、标题和副标题、带输入框">
+    <tdesign-demo-block title="02 组件风格" summary="消息组件风格">
       <themeDemo />
     </tdesign-demo-block>
   </div>
@@ -17,3 +16,19 @@
 import themeDemo from './theme.vue';
 import baseDemo from './base.vue';
 </script>
+
+<style lang="less">
+.tdesign-demo-main {
+  position: fixed;
+  transform: translate(0, 0);
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+.tdesign-mobile-demo {
+  position: fixed;
+  width: 100%;
+  height: calc(100% - 78px);
+  overflow: scroll;
+}
+</style>
diff --git a/src/message/demos/theme.vue b/src/message/demos/theme.vue
index 997acbc0..af839978 100644
--- a/src/message/demos/theme.vue
+++ b/src/message/demos/theme.vue
@@ -1,40 +1,52 @@
 <template>
   <div class="button-demo" style="margin: 0 16px">
-    <t-button block size="large" variant="outline" @click="showInfoMessage">普通通知</t-button>
-    <t-button block size="large" variant="outline" @click="showWarnMessage">警示提示通知</t-button>
-    <t-button block size="large" variant="outline" @click="showSuccessMessage">成功提示通知</t-button>
-    <t-button block size="large" variant="outline" @click="showErrorMessage">错误提示通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showInfoMessage">普通通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showSuccessMessage">成功通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showWarnMessage">警示通知</t-button>
+    <t-button block size="large" variant="outline" theme="primary" @click="showErrorMessage">错误通知</t-button>
   </div>
 </template>
 
 <script lang="ts" setup>
 import Message from '../index';
 
-const showInfoMessage = () =>
-  Message.info({
-    offset: [20, 32],
-    duration: 5000,
-    content: '这是一条普通通知信息',
-  });
-
-const showWarnMessage = () =>
-  Message.warning({
-    offset: [20, 32],
-    duration: -1,
-    content: '这是一条需要用户关注到的警示通知',
-  });
-
-const showSuccessMessage = () =>
-  Message.success({
-    offset: [20, 32],
-    duration: -1,
-    content: '这是一条需要成功的提示消息',
-  });
-
-const showErrorMessage = () =>
-  Message.error({
-    offset: [20, 32],
-    duration: -1,
-    content: '这是一条错误提示通知',
-  });
+const showMessage = (theme: string, content = '这是一条普通通知信息', duration = 5000) => {
+  if (Message[theme]) {
+    Message[theme]({
+      offset: [10, 16],
+      content,
+      duration,
+      icon: true,
+      zIndex: 20000,
+      context: document.querySelector('.tdesign-mobile-demo'),
+    });
+  }
+};
+
+const showInfoMessage = () => showMessage('info');
+
+const showWarnMessage = () => showMessage('warning', '这是一条需要用户关注到的警示通知');
+
+const showSuccessMessage = () => showMessage('success', '这是一条成功的提示消息');
+
+const showErrorMessage = () => showMessage('error', '这是一条错误提示通知');
 </script>
+
+<script lang="ts">
+export default {
+  name: 'ThemeDemo',
+};
+</script>
+
+<style lang="less" scoped>
+.tdesign-mobile-demo-block .button-demo {
+  .t-button {
+    border-radius: 6px;
+    &.t-size-l {
+      height: 48px;
+      font-size: 16px;
+      font-weight: bold;
+    }
+  }
+}
+</style>
diff --git a/src/message/index.ts b/src/message/index.ts
index ab833ecf..2071ced1 100644
--- a/src/message/index.ts
+++ b/src/message/index.ts
@@ -5,22 +5,32 @@ import { TdMessageProps, MessageThemeList } from './type';
 
 import './style';
 
-function create(props: TdMessageProps): void {
-  const visible = ref(false);
+interface MessageActionOptionsType extends TdMessageProps {
+  context?: HTMLElement;
+}
+
+function create(props: MessageActionOptionsType): void {
+  const { context, ...otherOptions } = props;
+
+  if (!context) {
+    console.error('未找到组件, 请确认 context 是否正确');
+    return;
+  }
+
   const root = document.createElement('div');
-  document.body.appendChild(root);
+  context.appendChild(root);
+  const visible = ref(false);
 
   const component = defineComponent({
     render: (): VNode =>
-      // @ts-ignore
       h(Message, {
-        ...props,
+        ...otherOptions,
         visible: visible.value,
-        onClose: () => {
+        onDurationEnd: () => {
           visible.value = false;
         },
-        onClosed: () => {
-          root.remove();
+        onCloseBtnClick: () => {
+          visible.value = false;
         },
       }),
   });
@@ -40,11 +50,8 @@ const defaultProps: TdMessageProps = {
   theme: 'info',
   visible: false,
   zIndex: 5000,
-  onClose: () => {},
-  onClosed: () => {},
-  onOpen: () => {},
-  onOpened: () => {},
-  onChange: () => {},
+  onDurationEnd: () => {},
+  onCloseBtnClick: () => {},
 };
 
 (['info', 'success', 'warning', 'error'] as MessageThemeList[]).forEach((theme: MessageThemeList): void => {
diff --git a/src/message/message.en-US.md b/src/message/message.en-US.md
index b98e4862..fc3e3dc1 100644
--- a/src/message/message.en-US.md
+++ b/src/message/message.en-US.md
@@ -5,29 +5,36 @@
 
 name | type | default | description | required
 -- | -- | -- | -- | --
-align | String | left | options：left/center。Typescript：`MessageAlignType` `type MessageAlignType = 'left' | 'center'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
-closeBtn | Boolean / Slot / Function | false | Typescript：` boolean | TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-content | String / Slot / Function | - | Typescript：`string | TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-duration | Number | 3000 | - | N
-icon | Boolean / Slot / Function | true | Typescript：` boolean | TNode`。| N
-marquee | Boolean / Object | false | Typescript：`boolean | DrawMarquee` `interface DrawMarquee { speed?: number; loop?: number; delay?: number }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
-offset | Array | - | Typescript：`Array<string | number>` | N
-theme | String | info | options：info/success/warning/error。Typescript：`MessageThemeList` `type MessageThemeList = 'info' | 'success' | 'warning' | 'error'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+align | String | left | options：left/center。Typescript：`MessageAlignType` `type MessageAlignType = 'left' \| 'center'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+closeBtn | String / Boolean / Slot / Function | undefined | Typescript：`string \| boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+content | String / Slot / Function | - | Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+duration | Number | 3000 | \- | N
+icon | Boolean / Slot / Function | true | Typescript：`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+link | String / Object / Slot / Function | - | Typescript：`string \| object \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+marquee | Boolean / Object | false | Typescript：`boolean \| DrawMarquee` `interface DrawMarquee { speed?: number; loop?: number; delay?: number }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+offset | Array | - | Typescript：`Array<string \| number>` | N
+theme | String | info | options：info/success/warning/error。Typescript：`MessageThemeList` `type MessageThemeList = 'info' \| 'success' \| 'warning' \| 'error'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
 visible | Boolean | false | `v-model` and `v-model:visible` is supported | N
 defaultVisible | Boolean | false | uncontrolled property | N
-zIndex | Number | - | - | N
-onChange | Function |  | Typescript：`(visible: boolean) => void`<br/> | N
-onClose | Function |  | Typescript：`() => void`<br/>close message event | N
-onClosed | Function |  | Typescript：`() => void`<br/> | N
-onOpen | Function |  | Typescript：`() => void`<br/> | N
-onOpened | Function |  | Typescript：`() => void`<br/> | N
+zIndex | Number | - | \- | N
+onChange | Function |  | Typescript：`(visible: boolean) => void`<br/>`deprecated` | N
+onClose | Function |  | Typescript：`(context: { trigger: 'close-click' \| 'duration-end', e?: MouseEvent }) => void`<br/>`deprecated`。close message event。Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+onCloseBtnClick | Function |  | Typescript：`(context: { e: MouseEvent }) => void`<br/> | N
+onClosed | Function |  | Typescript：`() => void`<br/>`deprecated` | N
+onDurationEnd | Function |  | Typescript：`() => void`<br/> | N
+onLinkClick | Function |  | 【developing】Typescript：`(context: { e: MouseEvent }) => void`<br/> | N
+onOpen | Function |  | Typescript：`() => void`<br/>`deprecated` | N
+onOpened | Function |  | Typescript：`() => void`<br/>`deprecated` | N
 
 ### Message Events
 
 name | params | description
 -- | -- | --
-change | `(visible: boolean)` | -
-close | - | close message event
-closed | - | -
-open | - | -
-opened | - | -
+change | `(visible: boolean)` | `deprecated`
+close | `(context: { trigger: 'close-click' \| 'duration-end', e?: MouseEvent })` | `deprecated`。close message event。Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts)
+close-btn-click | `(context: { e: MouseEvent })` | \-
+closed | \- | `deprecated`
+duration-end | \- | \-
+link-click | 【developing】`(context: { e: MouseEvent })` | \-
+open | \- | `deprecated`
+opened | \- | `deprecated`
diff --git a/src/message/message.md b/src/message/message.md
index ec2a198b..a5f3c938 100644
--- a/src/message/message.md
+++ b/src/message/message.md
@@ -5,29 +5,36 @@
 
 名称 | 类型 | 默认值 | 说明 | 必传
 -- | -- | -- | -- | --
-align | String | left | 文本对齐方式。可选项：left/center。TS 类型：`MessageAlignType` `type MessageAlignType = 'left' | 'center'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
-closeBtn | Boolean / Slot / Function | false | 关闭按钮，可以自定义。值为 true 显示默认关闭按钮，值为 false 不显示关闭按钮，也可以完全自定义按钮。TS 类型：`string | boolean | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-content | String / Slot / Function | - | 用于自定义消息弹出内容。TS 类型：`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+align | String | left | 文本对齐方式。可选项：left/center。TS 类型：`MessageAlignType` `type MessageAlignType = 'left' \| 'center'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+closeBtn | String / Boolean / Slot / Function | undefined | 关闭按钮，可以自定义。值为 true 显示默认关闭按钮，值为 false 不显示关闭按钮。值类型为 string 则直接显示值，如：“关闭”。也可以完全自定义按钮。TS 类型：`string \| boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+content | String / Slot / Function | - | 用于自定义消息弹出内容。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 duration | Number | 3000 | 消息内置计时器，计时到达时会触发 duration-end 事件。单位：毫秒。值为 0 则表示没有计时器。 | N
-icon | Boolean / Slot / Function | true | 消息提醒前面的图标。值为 true 则根据 theme 显示对应的图标，值为 false 则不显示图标，也可以完全自定义图标节点。TS 类型：`boolean | 'info' | 'bell'` | N
-marquee | Boolean / Object | false | 跑马灯效果。speed 指速度控制；loop 指循环播放次数，值为 -1 表示循环播放，值为 0 表示不循环播放；delay 表示延迟多久开始播放。TS 类型：`boolean | DrawMarquee` `interface DrawMarquee { speed?: number; loop?: number; delay?: number }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
-offset | Array | - | 相对于 placement 的偏移量，示例：[-10, 20] 或 ['10rpx', '8rpx']。TS 类型：`Array<string | number>` | N
-theme | String | info | 消息组件风格。可选项：info/success/warning/error。TS 类型：`MessageThemeList` `type MessageThemeList = 'info' | 'success' | 'warning' | 'error'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+icon | Boolean / Slot / Function | true | 用于自定义消息前面的图标，优先级大于 theme 设定的图标。值为 false 则不显示图标，值为 true 显示 theme 设定图标。TS 类型：`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+link | String / Object / Slot / Function | - | 链接名称。值为字符串表示链接名称，值为 Object 类型，表示透传至 Link。TS 类型：`string \| object \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+marquee | Boolean / Object | false | 跑马灯效果。speed 指速度控制；loop 指循环播放次数，值为 -1 表示循环播放，值为 0 表示不循环播放；delay 表示延迟多久开始播放。TS 类型：`boolean \| DrawMarquee` `interface DrawMarquee { speed?: number; loop?: number; delay?: number }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
+offset | Array | - | 相对于 placement 的偏移量，示例：[-10, 20] 或 ['10rpx', '8rpx']。TS 类型：`Array<string \| number>` | N
+theme | String | info | 消息组件风格。可选项：info/success/warning/error。TS 类型：`MessageThemeList` `type MessageThemeList = 'info' \| 'success' \| 'warning' \| 'error'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/message/type.ts) | N
 visible | Boolean | false | 是否显示，隐藏时默认销毁组件。支持语法糖 `v-model` 或 `v-model:visible` | N
 defaultVisible | Boolean | false | 是否显示，隐藏时默认销毁组件。非受控属性 | N
 zIndex | Number | - | 元素层级，样式默认为 5000 | N
-onChange | Function |  | TS 类型：`(visible: boolean) => void`<br/>可见性变化时触发 | N
-onClose | Function |  | TS 类型：`() => void`<br/>关闭Message时触发 | N
-onClosed | Function |  | TS 类型：`() => void`<br/>关闭Message时并且动画结束后触发 | N
-onOpen | Function |  | TS 类型：`() => void`<br/>展示Message时触发 | N
-onOpened | Function |  | TS 类型：`() => void`<br/>展示Message时并且动画结束后触发 | N
+onChange | Function |  | TS 类型：`(visible: boolean) => void`<br/>已废弃。可见性变化时触发 | N
+onClose | Function |  | TS 类型：`(context: { trigger: 'close-click' \| 'duration-end', e?: MouseEvent }) => void`<br/>已废弃。关闭消息时触发。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+onCloseBtnClick | Function |  | TS 类型：`(context: { e: MouseEvent }) => void`<br/>当关闭按钮存在时，用户点击关闭按钮触发 | N
+onClosed | Function |  | TS 类型：`() => void`<br/>已废弃。关闭消息并且动画结束后触发 | N
+onDurationEnd | Function |  | TS 类型：`() => void`<br/>计时结束后触发 | N
+onLinkClick | Function |  | 【开发中】TS 类型：`(context: { e: MouseEvent }) => void`<br/>当link链接存在时，点击链接文本时触发 | N
+onOpen | Function |  | TS 类型：`() => void`<br/>已废弃。展示Message时触发 | N
+onOpened | Function |  | TS 类型：`() => void`<br/>已废弃。展示Message时并且动画结束后触发 | N
 
 ### Message Events
 
 名称 | 参数 | 描述
 -- | -- | --
-change | `(visible: boolean)` | 可见性变化时触发
-close | \- | 关闭Message时触发
-closed | \- | 关闭Message时并且动画结束后触发
-open | \- | 展示Message时触发
-opened | \- | 展示Message时并且动画结束后触发
+change | `(visible: boolean)` | 已废弃。可见性变化时触发
+close | `(context: { trigger: 'close-click' \| 'duration-end', e?: MouseEvent })` | 已废弃。关闭消息时触发。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts)
+close-btn-click | `(context: { e: MouseEvent })` | 当关闭按钮存在时，用户点击关闭按钮触发
+closed | \- | 已废弃。关闭消息并且动画结束后触发
+duration-end | \- | 计时结束后触发
+link-click | `(context: { e: MouseEvent })` | 【开发中】当link链接存在时，点击链接文本时触发
+open | \- | 已废弃。展示Message时触发
+opened | \- | 已废弃。展示Message时并且动画结束后触发
diff --git a/src/message/message.vue b/src/message/message.vue
index 2f8e0df5..b1b92e17 100644
--- a/src/message/message.vue
+++ b/src/message/message.vue
@@ -1,19 +1,19 @@
 <template>
-  <transition name="message" @after-leave="afterLeave" @after-enter="afterEnter">
+  <transition name="message">
     <div v-if="currentVisible" ref="root" :class="rootClasses" :style="rootStyles">
-      <t-node v-if="computedPrefixIcon" :content="computedPrefixIcon"></t-node>
+      <t-node v-if="computedPrefixIcon" :content="computedPrefixIcon" :class="`${name}__icon--left`"></t-node>
       <div ref="textWrapDOM" :class="textWrapClasses">
         <div
           ref="textDOM"
           :class="`${name}__text`"
           :style="scroll.marquee ? animateStyle : ''"
-          @transitionend="handleTransitionend()"
+          @transitionend="handleTransitionend"
         >
           <t-node v-if="computedContent" :content="computedContent"></t-node>
         </div>
       </div>
-      <div v-if="computedCloseBtn" @click="onClose">
-        <t-node :content="computedCloseBtn"></t-node>
+      <div v-if="computedCloseBtn" :class="`${name}__close-wrap`" @click="onCloseBtnClick">
+        <t-node :content="computedCloseBtn" :class="`${name}__icon--right`"></t-node>
       </div>
     </div>
   </transition>
@@ -34,7 +34,6 @@ import {
 } from 'vue';
 import { CheckCircleFilledIcon, ErrorCircleFilledIcon, CloseIcon } from 'tdesign-icons-vue-next';
 import { isFunction } from 'lodash';
-import { off } from 'process';
 import messageProps from './props';
 import { DrawMarquee } from './type';
 import config from '../config';
@@ -53,7 +52,7 @@ export default defineComponent({
   name,
   components: { TNode },
   props: messageProps,
-  emits: ['change', 'open', 'opened', 'close', 'closed'],
+  emits: ['durationEnd', 'closeBtnClick'],
   setup(props: any, context) {
     const emitEvent = useEmitEvent(props, context.emit);
     const internalInstance = getCurrentInstance();
@@ -68,12 +67,12 @@ export default defineComponent({
         marquee: false,
         speed: 50,
         loop: -1, // 值为 -1 表示循环播放，值为 0 表示不循环播放
-        delay: 0,
+        delay: 300,
       },
     });
 
     const { visible, modelValue } = toRefs(props);
-    const [currentVisible, setVisible] = useVModel(visible, modelValue, props.defaultVisible, props.onChange);
+    const [currentVisible, setVisible] = useVModel(visible, modelValue, props.defaultVisible);
     const rootClasses = computed(() => ({
       [name]: true,
       [`${name}--${props.theme}`]: true,
@@ -129,8 +128,7 @@ export default defineComponent({
         return renderTNode(internalInstance, 'closeBtn');
       }
       if (closeBtn) {
-        const closeIcon = h(CloseIcon);
-        return closeIcon;
+        return h(CloseIcon);
       }
       return null;
     });
@@ -149,17 +147,20 @@ export default defineComponent({
       if (!props?.marquee || (props?.marquee as DrawMarquee)?.loop === 0) {
         return;
       }
-      // 初始化动画参数
-      if (typeof props.marquee === 'boolean') {
-        state.scroll = { ...state.scroll, marquee: props.marquee };
-      }
-      const marquee = props.marquee as DrawMarquee;
+
+      const { loop, speed, delay } = state.scroll;
+
       state.scroll = {
         marquee: true,
-        loop: typeof marquee?.loop === 'undefined' ? state.scroll.loop : marquee.loop,
-        speed: marquee.speed ?? state.scroll.speed,
-        delay: marquee.delay ?? state.scroll.delay,
+        // 负数统一当作循环播放
+        loop: Math.max(props.marquee?.loop, -1) || loop,
+        // 速度必须为正数
+        speed: Math.max(props.marquee?.speed, 1) || speed,
+        // 延迟不可为负数
+        delay: Math.max(props.marquee?.delay, 0) || delay,
       };
+      state.offset = 0;
+
       // 设置动画
       setTimeout(() => {
         const textWrapDOMWidth = textWrapDOM.value?.getBoundingClientRect().width;
@@ -173,16 +174,22 @@ export default defineComponent({
 
     // 动画结束后，初始化动画
     const handleTransitionend = () => {
+      resetTransition();
+
+      if (state.scroll.loop === -1) {
+        return;
+      }
+
       state.scroll.loop = --state.scroll.loop;
+
       if (state.scroll.loop === 0) {
-        state.scroll = {
-          ...state.scroll,
-          marquee: false,
-        };
-        return;
+        state.scroll.marquee = false;
       }
-      state.offset = state.listWidth;
+    };
+
+    const resetTransition = () => {
       state.duration = 0;
+      state.offset = state.listWidth;
 
       setTimeout(() => {
         state.offset = -state.itemWidth;
@@ -190,8 +197,8 @@ export default defineComponent({
       }, 0);
     };
 
-    const onClose = () => {
-      emitEvent('close');
+    const onCloseBtnClick = () => {
+      emitEvent('closeBtnClick');
       setVisible(false);
     };
 
@@ -199,7 +206,7 @@ export default defineComponent({
       if (props.duration > 0) {
         setTimeout(() => {
           emitEvent('durationEnd');
-          onClose();
+          onCloseBtnClick();
         }, props.duration);
       }
     };
@@ -216,14 +223,9 @@ export default defineComponent({
       () => currentVisible.value,
       (val) => {
         if (val === false) return;
-        emitEvent('open');
         setVisible(true);
         handleDuration();
-        nextTick(() => {
-          state.offset = state.listWidth;
-          state.duration = 0;
-          handleScrolling();
-        });
+        nextTick(handleScrolling);
       },
     );
 
@@ -240,10 +242,8 @@ export default defineComponent({
       textWrapDOM,
       textDOM,
       animateStyle,
-      onClose,
+      onCloseBtnClick,
       handleTransitionend,
-      afterEnter: () => emitEvent('opened'),
-      afterLeave: () => emitEvent('closed'),
     };
   },
 });
diff --git a/src/message/props.ts b/src/message/props.ts
index 65d44e28..2f7aad8d 100644
--- a/src/message/props.ts
+++ b/src/message/props.ts
@@ -19,8 +19,8 @@ export default {
   },
   /** 关闭按钮，可以自定义。值为 true 显示默认关闭按钮，值为 false 不显示关闭按钮。值类型为 string 则直接显示值，如：“关闭”。也可以完全自定义按钮 */
   closeBtn: {
-    type: [Boolean, Function] as PropType<TdMessageProps['closeBtn']>,
-    default: false,
+    type: [String, Boolean, Function] as PropType<TdMessageProps['closeBtn']>,
+    default: undefined,
   },
   /** 用于自定义消息弹出内容 */
   content: {
@@ -31,11 +31,15 @@ export default {
     type: Number,
     default: 3000,
   },
-  /** 消息提醒前面的图标。值为 true 则根据 theme 显示对应的图标，值为 false 则不显示图标。值为 'info' 或 'bell' 则显示组件内置图标。也可以完全自定义图标节点 */
+  /** 用于自定义消息前面的图标，优先级大于 theme 设定的图标。值为 false 则不显示图标，值为 true 显示 theme 设定图标 */
   icon: {
     type: [Boolean, Function] as PropType<TdMessageProps['icon']>,
     default: true,
   },
+  /** 链接名称。值为字符串表示链接名称，值为 Object 类型，表示透传至 Link */
+  link: {
+    type: [String, Object, Function] as PropType<TdMessageProps['link']>,
+  },
   /** 跑马灯效果。speed 指速度控制；loop 指循环播放次数，值为 -1 表示循环播放，值为 0 表示不循环播放；delay 表示延迟多久开始播放 */
   marquee: {
     type: [Boolean, Object] as PropType<TdMessageProps['marquee']>,
@@ -69,14 +73,20 @@ export default {
   zIndex: {
     type: Number,
   },
-  /** 可见性变化时触发 */
+  /** 已废弃。可见性变化时触发 */
   onChange: Function as PropType<TdMessageProps['onChange']>,
-  /** 关闭消息时触发 */
+  /** 已废弃。关闭消息时触发 */
   onClose: Function as PropType<TdMessageProps['onClose']>,
-  /** 关闭Message时并且动画结束后触发 */
+  /** 当关闭按钮存在时，用户点击关闭按钮触发 */
+  onCloseBtnClick: Function as PropType<TdMessageProps['onCloseBtnClick']>,
+  /** 已废弃。关闭消息并且动画结束后触发 */
   onClosed: Function as PropType<TdMessageProps['onClosed']>,
-  /** 展示Message时触发 */
+  /** 计时结束后触发 */
+  onDurationEnd: Function as PropType<TdMessageProps['onDurationEnd']>,
+  /** 当link链接存在时，点击链接文本时触发 */
+  onLinkClick: Function as PropType<TdMessageProps['onLinkClick']>,
+  /** 已废弃。展示Message时触发 */
   onOpen: Function as PropType<TdMessageProps['onOpen']>,
-  /** 展示Message时并且动画结束后触发 */
+  /** 已废弃。展示Message时并且动画结束后触发 */
   onOpened: Function as PropType<TdMessageProps['onOpened']>,
 };
diff --git a/src/message/style/index.js b/src/message/style/index.js
index a433a27b..b19cb183 100644
--- a/src/message/style/index.js
+++ b/src/message/style/index.js
@@ -1,1 +1,1 @@
-import '../../_common/style/mobile/components/message/_index.less';
+import '../../_common/style/mobile/components/message/v2/_index.less';
diff --git a/src/message/type.ts b/src/message/type.ts
index 9ad6056f..0369c900 100644
--- a/src/message/type.ts
+++ b/src/message/type.ts
@@ -15,7 +15,7 @@ export interface TdMessageProps {
   /**
    * 关闭按钮，可以自定义。值为 true 显示默认关闭按钮，值为 false 不显示关闭按钮。值类型为 string 则直接显示值，如：“关闭”。也可以完全自定义按钮
    */
-  closeBtn?: boolean | TNode;
+  closeBtn?: string | boolean | TNode;
   /**
    * 用于自定义消息弹出内容
    */
@@ -26,10 +26,14 @@ export interface TdMessageProps {
    */
   duration?: number;
   /**
-   * 消息提醒前面的图标。值为 true 则根据 theme 显示对应的图标，值为 false 则不显示图标。值为 'info' 或 'bell' 则显示组件内置图标。也可以完全自定义图标节点
+   * 用于自定义消息前面的图标，优先级大于 theme 设定的图标。值为 false 则不显示图标，值为 true 显示 theme 设定图标
    * @default true
    */
   icon?: boolean | TNode;
+  /**
+   * 链接名称。值为字符串表示链接名称，值为 Object 类型，表示透传至 Link
+   */
+  link?: string | object | TNode;
   /**
    * 跑马灯效果。speed 指速度控制；loop 指循环播放次数，值为 -1 表示循环播放，值为 0 表示不循环播放；delay 表示延迟多久开始播放
    * @default false
@@ -65,22 +69,39 @@ export interface TdMessageProps {
   zIndex?: number;
   /**
    * 可见性变化时触发
+   * @deprecated
    */
   onChange?: (visible: boolean) => void;
   /**
    * 关闭消息时触发
+   * @deprecated
+   */
+  onClose?: (context: { trigger: 'close-click' | 'duration-end'; e?: MouseEvent }) => void;
+  /**
+   * 当关闭按钮存在时，用户点击关闭按钮触发
    */
-  onClose?: (context?: { trigger: 'duration' | 'close-click' }) => void;
+  onCloseBtnClick?: (context: { e: MouseEvent }) => void;
   /**
-   * 关闭Message时并且动画结束后触发
+   * 关闭消息并且动画结束后触发
+   * @deprecated
    */
   onClosed?: () => void;
+  /**
+   * 计时结束后触发
+   */
+  onDurationEnd?: () => void;
+  /**
+   * 当link链接存在时，点击链接文本时触发
+   */
+  onLinkClick?: (context: { e: MouseEvent }) => void;
   /**
    * 展示Message时触发
+   * @deprecated
    */
   onOpen?: () => void;
   /**
    * 展示Message时并且动画结束后触发
+   * @deprecated
    */
   onOpened?: () => void;
 }
diff --git a/src/upload/demos/base.vue b/src/upload/demos/base.vue
index 471eb3b6..6caaf8c6 100644
--- a/src/upload/demos/base.vue
+++ b/src/upload/demos/base.vue
@@ -1,33 +1,36 @@
 <template>
   <div class="upload-demo">
-    <div class="upload-title">上传图片</div>
+    <div class="upload-title">单选上传</div>
     <t-upload
-      :default-files="files"
+      :default-files="[]"
       :multiple="false"
+      :max="1"
+      :size-limit="{ size: 3000000, unit: 'B' }"
       accept="image/png"
       action="//service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
+      @validate="onValidate"
     >
     </t-upload>
   </div>
 </template>
-<script setup lang="ts">
-const files = [
-  {
-    url: 'https://tdesign.gtimg.com/site/upload1.png',
-    name: 'uploaded1.png',
-    type: 'image',
-  },
-];
+
+<script lang="ts" setup>
+import { Message } from 'tdesign-mobile-vue';
+
+const onValidate = (context: any) => {
+  if (context.type === 'FILE_OVER_SIZE_LIMIT') {
+    Message.warning('文件大小超出上限');
+  }
+};
 </script>
 
 <style scoped lang="less">
 .upload-demo {
   background: #fff;
   .upload-title {
-    font-family: PingFangSC-Regular;
-    font-size: 14px;
-    color: #999999;
-    padding: 12px 0 12px 16px;
+    font-size: 16px;
+    color: rgba(0, 0, 0, 0.9);
+    padding: 12px 16px 0;
   }
 }
 </style>
diff --git a/src/upload/demos/mobile.vue b/src/upload/demos/mobile.vue
index 2e2af27e..139bc347 100644
--- a/src/upload/demos/mobile.vue
+++ b/src/upload/demos/mobile.vue
@@ -2,15 +2,19 @@
   <div class="tdesign-mobile-demo">
     <h1 class="title">Upload上传</h1>
     <p class="summary">用于相册读取或拉起拍照的图片上传功能。</p>
-    <tdesign-demo-block title="01 类型" summary="单选上传图片">
+    <tdesign-demo-block title="01 组件类型" summary="单选上传">
       <BaseDemo />
     </tdesign-demo-block>
-    <tdesign-demo-block summary="多选上传图片">
+    <tdesign-demo-block summary="多选上传">
       <MultipleDemo />
     </tdesign-demo-block>
+    <tdesign-demo-block title="02 组件状态" summary="加载状态">
+      <StatusDemo />
+    </tdesign-demo-block>
   </div>
 </template>
 <script setup lang="ts">
 import BaseDemo from './base.vue';
 import MultipleDemo from './multiple.vue';
+import StatusDemo from './status.vue';
 </script>
diff --git a/src/upload/demos/multiple.vue b/src/upload/demos/multiple.vue
index 1d041c33..ea4f9c23 100644
--- a/src/upload/demos/multiple.vue
+++ b/src/upload/demos/multiple.vue
@@ -1,10 +1,10 @@
 <template>
   <div class="upload-demo">
-    <div class="upload-title">多选上传图片</div>
+    <div class="upload-title">多选上传</div>
     <t-upload
-      v-model="files"
-      :multiple="true"
-      :max="max"
+      :default-files="files"
+      multiple
+      :max="10"
       :grid-config="gridConfig"
       :action="action"
       :on-fail="onFail"
@@ -47,24 +47,22 @@ const onRemove = ({ index, file, e }: UploadRemoveContext) => {
 const onSelectChange = (files: Array<UploadFile>) => {
   console.log('====onSelectChange', files);
 };
-const max = 10;
 const action = 'https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo';
 const files = ref([
   {
-    url: 'https://tdesign.gtimg.com/site/upload1.png',
+    url: 'https://tdesign.gtimg.com/miniprogram/images/example4.png',
     name: 'uploaded1.png',
     type: 'image',
   },
   {
-    url: 'https://tdesign.gtimg.com/site/upload2.png',
+    url: 'https://tdesign.gtimg.com/miniprogram/images/example6.png',
     name: 'uploaded2.png',
     type: 'image',
   },
   {
-    url: 'https://tdesign.gtimg.com/site/upload1.png',
+    url: 'https://tdesign.gtimg.com/miniprogram/images/example5.png',
     name: 'uploaded3.png',
     type: 'image',
-    status: 'fail',
   },
 ]);
 </script>
@@ -72,10 +70,9 @@ const files = ref([
 .upload-demo {
   background: #fff;
   .upload-title {
-    font-family: PingFangSC-Regular;
-    font-size: 14px;
-    color: #999999;
-    padding: 12px 0 12px 16px;
+    font-size: 16px;
+    color: rgba(0, 0, 0, 0.9);
+    padding: 12px 16px 0;
   }
 }
 </style>
diff --git a/src/upload/demos/status.vue b/src/upload/demos/status.vue
new file mode 100644
index 00000000..dd2c2cef
--- /dev/null
+++ b/src/upload/demos/status.vue
@@ -0,0 +1,72 @@
+<template>
+  <div class="upload-demo">
+    <div class="upload-title">上传图片</div>
+    <t-upload
+      :default-files="files"
+      :multiple="false"
+      accept="image/png"
+      action="//service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
+    >
+    </t-upload>
+  </div>
+
+  <div class="upload-demo__title">上传失败</div>
+
+  <div class="upload-demo">
+    <div class="upload-title">上传图片</div>
+    <t-upload
+      :default-files="failFiles"
+      :multiple="false"
+      accept="image/png"
+      action="//service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
+    >
+    </t-upload>
+  </div>
+</template>
+<script setup lang="ts">
+const files = [
+  {
+    url: 'https://tdesign.gtimg.com/site/upload1.png',
+    name: 'uploaded1.png',
+    type: 'image',
+    status: 'progress',
+  },
+  {
+    url: 'https://tdesign.gtimg.com/site/upload1.png',
+    name: 'uploaded1.png',
+    type: 'image',
+    status: 'progress',
+    percent: 68,
+  },
+];
+
+const failFiles = [
+  {
+    url: 'https://tdesign.gtimg.com/site/upload1.png',
+    name: 'uploaded1.png',
+    type: 'image',
+    status: 'fail',
+  },
+];
+</script>
+
+<style scoped lang="less">
+.upload-demo {
+  background: #fff;
+
+  & + & {
+    margin-top: 16px;
+  }
+
+  &__title {
+    font-size: 14px;
+    margin: 24px 16px 16px;
+    color: rgba(0, 0, 0, 0.6);
+  }
+  .upload-title {
+    font-size: 16px;
+    color: rgba(0, 0, 0, 0.9);
+    padding: 12px 16px 0;
+  }
+}
+</style>
diff --git a/src/upload/props.ts b/src/upload/props.ts
index 88138dca..f131ad25 100644
--- a/src/upload/props.ts
+++ b/src/upload/props.ts
@@ -13,61 +13,55 @@ export default {
     type: String,
     default: '',
   },
-  /** 上传接口 */
+  /** 上传接口。设接口响应数据为字段 `response`，那么 `response.error` 存在时会判断此次上传失败，并显示错误文本信息；`response.url` 会作为文件上传成功后的地址，并使用该地址显示图片或文件 */
   action: {
     type: String,
     default: '',
   },
   /** 是否允许重复上传相同文件名的文件 */
   allowUploadDuplicateFile: Boolean,
-  /** 是否选取文件后自动上传 */
+  /** 是否在选择文件后自动发起请求上传文件 */
   autoUpload: {
     type: Boolean,
     default: true,
   },
-  /** 上传文件之前的钩子，参数为上传的文件，返回值决定是否上传 */
+  /** 如果是自动上传模式 `autoUpload=true`，表示单个文件上传之前的钩子函数，若函数返回值为 `false` 则表示不上传当前文件。<br/>如果是非自动上传模式 `autoUpload=false`，函数返回值为 `false` 时表示从上传文件中剔除当前文件 */
   beforeUpload: {
     type: Function as PropType<TdUploadProps['beforeUpload']>,
   },
-  /** 上传文件时所需的额外数据 */
+  /** 上传请求所需的额外字段，默认字段有 `file`，表示文件信息。可以添加额外的文件名字段，如：`{file_name: "custom-file-name.txt"}`。`autoUpload=true` 时有效。也可以使用 `formatRequest` 完全自定义上传请求的字段 */
   data: {
     type: Object as PropType<TdUploadProps['data']>,
   },
-  /** 删除图标。值为空，使用默认图标渲染；值为 slot 则表示使用插槽渲染；其他值无效。 */
-  deleteBtn: {
-    type: [String, Function] as PropType<TdUploadProps['deleteBtn']>,
-  },
   /** 是否禁用 */
   disabled: Boolean,
-  /** 【开发中】用于完全自定义文件列表内容 */
+  /** 用于完全自定义文件列表内容 */
   fileListDisplay: {
     type: Function as PropType<TdUploadProps['fileListDisplay']>,
   },
-  /** 已上传文件列表 */
+  /** 已上传文件列表，同 `value`。TS 类型：`UploadFile` */
   files: {
     type: Array as PropType<TdUploadProps['files']>,
-  },
-  modelValue: {
-    type: Array as PropType<TdUploadProps['files']>,
     default: undefined,
   },
-  /** 已上传文件列表，非受控属性 */
+  /** 已上传文件列表，同 `value`。TS 类型：`UploadFile`，非受控属性 */
   defaultFiles: {
     type: Array as PropType<TdUploadProps['defaultFiles']>,
+    default: (): TdUploadProps['defaultFiles'] => [],
   },
-  /** 文件上传前转换文件数据 */
+  /** 转换文件 `UploadFile` 的数据结构，可新增或修改 `UploadFile` 的属性，注意不能删除 `UploadFile` 属性。`action` 存在时有效 */
   format: {
     type: Function as PropType<TdUploadProps['format']>,
   },
-  /** 用于格式化文件上传后的响应数据。error 用于显示错误提示，如果 error 值为真，组件会判定为上传失败；url 用于上传文件/图片地址。 */
+  /** 用于新增或修改文件上传请求参数。`action` 存在时有效。一个请求上传一个文件时，默认请求字段有 `file`；<br/>一个请求上传多个文件时，默认字段有 `file[0]/file[1]/file[2]/.../length`，其中 `length` 表示本次上传的文件数量。<br/>⚠️非常注意，此处的 `file[0]/file[1]` 仅仅是一个字段名，并非表示 `file` 是一个数组，接口获取字段时注意区分。<br/>可以使用 `name` 定义 `file` 字段的别名，也可以使用 `formatRequest` 自定义任意字段 */
+  formatRequest: {
+    type: Function as PropType<TdUploadProps['formatRequest']>,
+  },
+  /** 用于格式化文件上传后的接口响应数据，`response` 便是接口响应的原始数据。`action` 存在时有效。<br/> 此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒，如果存在会判定为本次上传失败。<br/> 此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接 */
   formatResponse: {
     type: Function as PropType<TdUploadProps['formatResponse']>,
   },
-  /** upload组件每行上传图片列数以及图片的宽度和高度 */
-  gridConfig: {
-    type: Object as PropType<TdUploadProps['gridConfig']>,
-  },
-  /** 设置上传的请求头部 */
+  /** 设置上传的请求头部，`action` 存在时有效 */
   headers: {
     type: Object as PropType<TdUploadProps['headers']>,
   },
@@ -89,41 +83,37 @@ export default {
       return ['POST', 'GET', 'PUT', 'OPTION', 'PATCH', 'post', 'get', 'put', 'option', 'patch'].includes(val);
     },
   },
-  /** 是否支持多选文件 */
+  /** 支持多文件上传 */
   multiple: Boolean,
-  /** 自定义上传方法。返回值 status 表示上传成功或失败，error 表示上传失败的原因，response 表示请求上传成功后的返回数据，response.url 表示上传成功后的图片地址。示例一：`{ status: 'fail', error: '上传失败', response }`。示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }` */
+  /** 自定义上传方法。返回值 `status` 表示上传成功或失败；`error` 或 `response.error` 表示上传失败的原因；<br/>`response` 表示请求上传成功后的返回数据，`response.url` 表示上传成功后的图片/文件地址，`response.files` 表示一个请求上传多个文件/图片后的返回值。<br/>示例一：`{ status: 'fail', error: '上传失败', response }`。<br/>示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。<br/> 示例三：`{ status: 'success', files: [{ url: 'https://xxx.png', name: 'xxx.png' }]}` */
   requestMethod: {
     type: Function as PropType<TdUploadProps['requestMethod']>,
   },
-  /** 图片文件大小限制，单位 KB。可选单位有：`'B' | 'KB' | 'MB' | 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }` */
+  /** 图片文件大小限制，默认单位 KB。可选单位有：`'B' | 'KB' | 'MB' | 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }` */
   sizeLimit: {
     type: [Number, Object] as PropType<TdUploadProps['sizeLimit']>,
   },
-  /** 触发上传的内容 */
-  trigger: {
-    type: [String, Function] as PropType<TdUploadProps['trigger']>,
-  },
-  /** 是否显示为模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传 */
+  /** 是否在请求时间超过 300ms 后显示模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传。 */
   useMockProgress: {
     type: Boolean,
     default: true,
   },
   /** 上传请求时是否携带 cookie */
   withCredentials: Boolean,
-  /** 点击「取消上传」时触发 */
-  onCancelUpload: Function as PropType<TdUploadProps['onCancelUpload']>,
-  /** 已上传文件列表发生变化时触发 */
+  /** 已上传文件列表发生变化时触发，`trigger` 表示触发本次的来源 */
   onChange: Function as PropType<TdUploadProps['onChange']>,
-  /** 上传失败后触发 */
+  /** 上传失败后触发。`response` 指接口响应结果，`response.error` 会作为错误文本提醒。如果希望判定为上传失败，但接口响应数据不包含 `error` 字段，可以使用 `formatResponse` 格式化 `response` 数据结构。如果是多文件多请求上传场景，请到事件 `onOneFileFail` 中查看 `response` */
   onFail: Function as PropType<TdUploadProps['onFail']>,
-  /** 点击预览时触发 */
+  /** 点击图片预览时触发，文件没有预览 */
   onPreview: Function as PropType<TdUploadProps['onPreview']>,
-  /** 上传进度变化时触发，真实进度和模拟进度都会触发。type 值为 real 表示真实上传进度，type 值为 mock 表示模拟上传进度 */
+  /** 上传进度变化时触发，真实进度和模拟进度都会触发。<br/>⚠️ 原始上传请求，小文件的上传进度只有 0 和 100，故而不会触发 `progress` 事件；只有大文件才有真实的中间进度。如果你希望很小的文件也显示上传进度，保证 `useMockProgress=true` 的情况下，设置 `mockProgressDuration` 为更小的值。<br/>参数 `options.type=real` 表示真实上传进度，`options.type=mock` 表示模拟上传进度 */
   onProgress: Function as PropType<TdUploadProps['onProgress']>,
   /** 移除文件时触发 */
   onRemove: Function as PropType<TdUploadProps['onRemove']>,
-  /** 文件选择后，上传开始前，触发 */
+  /** 选择文件或图片之后，上传之前，触发该事件 */
   onSelectChange: Function as PropType<TdUploadProps['onSelectChange']>,
-  /** 上传成功后触发，`context.currentFiles` 表示当次请求上传的文件，`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br />⚠️ `context.file` 请勿使用 */
+  /** 上传成功后触发。<br/>`context.currentFiles` 表示当次请求上传的文件（无论成功或失败），`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br/>`context.results` 表示单次选择全部文件上传成功后的响应结果，可以在这个字段存在时提醒用户上传成功或失败。<br /> */
   onSuccess: Function as PropType<TdUploadProps['onSuccess']>,
+  /** 文件上传校验结束事件，文件数量超出、文件大小超出限制、文件同名、`beforeAllFilesUpload` 返回值为假、`beforeUpload` 返回值为假等场景会触发。<br/>注意：如果设置允许上传同名文件，即 `allowUploadDuplicateFile=true`，则不会因为文件重名触发该事件。<br/>结合 `status` 和 `tips` 可以在组件中呈现不同类型的错误（或告警）提示 */
+  onValidate: Function as PropType<TdUploadProps['onValidate']>,
 };
diff --git a/src/upload/style/index.js b/src/upload/style/index.js
index f91323fb..62eeb1db 100644
--- a/src/upload/style/index.js
+++ b/src/upload/style/index.js
@@ -1,1 +1,1 @@
-import '../../_common/style/mobile/components/upload/_index.less';
+import '../../_common/style/mobile/components/upload/v2/_index.less';
diff --git a/src/upload/type.ts b/src/upload/type.ts
index f57243a5..78040f94 100644
--- a/src/upload/type.ts
+++ b/src/upload/type.ts
@@ -5,16 +5,16 @@
  * */
 
 import { ImageProps } from '../image';
-import { TNode } from '../common';
+import { PlainObject, TNode, UploadDisplayDragEvents } from '../common';
 
-export interface TdUploadProps {
+export interface TdUploadProps<T extends UploadFile = UploadFile> {
   /**
    * 接受上传的文件类型，[查看 W3C示例](https://www.w3schools.com/tags/att_input_accept.asp)，[查看 MDN 示例](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file)
    * @default ''
    */
   accept?: string;
   /**
-   * 上传接口
+   * 上传接口。设接口响应数据为字段 `response`，那么 `response.error` 存在时会判断此次上传失败，并显示错误文本信息；`response.url` 会作为文件上传成功后的地址，并使用该地址显示图片或文件
    * @default ''
    */
   action?: string;
@@ -24,61 +24,50 @@ export interface TdUploadProps {
    */
   allowUploadDuplicateFile?: boolean;
   /**
-   * 是否选取文件后自动上传
+   * 是否在选择文件后自动发起请求上传文件
    * @default true
    */
   autoUpload?: boolean;
   /**
-   * 上传文件之前的钩子，参数为上传的文件，返回值决定是否上传
+   * 如果是自动上传模式 `autoUpload=true`，表示单个文件上传之前的钩子函数，若函数返回值为 `false` 则表示不上传当前文件。<br/>如果是非自动上传模式 `autoUpload=false`，函数返回值为 `false` 时表示从上传文件中剔除当前文件
    */
-  beforeUpload?: (file: File | UploadFile) => boolean | Promise<boolean>;
+  beforeUpload?: (file: UploadFile) => boolean | Promise<boolean>;
   /**
-   * 上传文件时所需的额外数据
+   * 上传请求所需的额外字段，默认字段有 `file`，表示文件信息。可以添加额外的文件名字段，如：`{file_name: "custom-file-name.txt"}`。`autoUpload=true` 时有效。也可以使用 `formatRequest` 完全自定义上传请求的字段
    */
-  data?: Record<string, any> | ((file: File) => Record<string, any>);
-  /**
-   * 删除图标。值为空，使用默认图标渲染；值为 slot 则表示使用插槽渲染；其他值无效。
-   */
-  deleteBtn?: string | TNode;
+  data?: Record<string, any> | ((files: UploadFile[]) => Record<string, any>);
   /**
    * 是否禁用
-   * @default false
    */
   disabled?: boolean;
   /**
-   * 【开发中】用于完全自定义文件列表内容
-   */
-  fileListDisplay?: TNode;
-  /**
-   * 已上传文件列表
+   * 用于完全自定义文件列表内容
    */
-  files?: Array<UploadFile>;
+  fileListDisplay?: TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>;
   /**
-   * 已上传文件列表，非受控属性
+   * 已上传文件列表，同 `value`。TS 类型：`UploadFile`
+   * @default []
    */
-  defaultFiles?: Array<UploadFile>;
+  files?: Array<T>;
   /**
-   * 已上传文件列表
+   * 已上传文件列表，同 `value`。TS 类型：`UploadFile`，非受控属性
+   * @default []
    */
-  modelValue?: Array<UploadFile>;
+  defaultFiles?: Array<T>;
   /**
-   * 文件上传前转换文件数据
+   * 转换文件 `UploadFile` 的数据结构，可新增或修改 `UploadFile` 的属性，注意不能删除 `UploadFile` 属性。`action` 存在时有效
    */
   format?: (file: File) => UploadFile;
   /**
-   * 用于格式化文件上传后的响应数据。error 用于显示错误提示，如果 error 值为真，组件会判定为上传失败；url 用于上传文件/图片地址。
+   * 用于新增或修改文件上传请求参数。`action` 存在时有效。一个请求上传一个文件时，默认请求字段有 `file`；<br/>一个请求上传多个文件时，默认字段有 `file[0]/file[1]/file[2]/.../length`，其中 `length` 表示本次上传的文件数量。<br/>⚠️非常注意，此处的 `file[0]/file[1]` 仅仅是一个字段名，并非表示 `file` 是一个数组，接口获取字段时注意区分。<br/>可以使用 `name` 定义 `file` 字段的别名，也可以使用 `formatRequest` 自定义任意字段
    */
-  formatResponse?: (response: any, context: FormatResponseContext) => ResponseType;
+  formatRequest?: (requestData: { [key: string]: any }) => { [key: string]: any };
   /**
-   * upload组件每行上传图片列数以及图片的宽度和高度
+   * 用于格式化文件上传后的接口响应数据，`response` 便是接口响应的原始数据。`action` 存在时有效。<br/> 此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒，如果存在会判定为本次上传失败。<br/> 此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接
    */
-  gridConfig?: {
-    column?: number;
-    width?: number;
-    height?: number;
-  };
+  formatResponse?: (response: any, context: FormatResponseContext) => ResponseType;
   /**
-   * 设置上传的请求头部
+   * 设置上传的请求头部，`action` 存在时有效
    */
   headers?: { [key: string]: string };
   /**
@@ -96,24 +85,20 @@ export interface TdUploadProps {
    */
   method?: 'POST' | 'GET' | 'PUT' | 'OPTION' | 'PATCH' | 'post' | 'get' | 'put' | 'option' | 'patch';
   /**
-   * 是否支持多选文件
+   * 支持多文件上传
    * @default false
    */
   multiple?: boolean;
   /**
-   * 自定义上传方法。返回值 status 表示上传成功或失败，error 表示上传失败的原因，response 表示请求上传成功后的返回数据，response.url 表示上传成功后的图片地址。示例一：`{ status: 'fail', error: '上传失败', response }`。示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`
+   * 自定义上传方法。返回值 `status` 表示上传成功或失败；`error` 或 `response.error` 表示上传失败的原因；<br/>`response` 表示请求上传成功后的返回数据，`response.url` 表示上传成功后的图片/文件地址，`response.files` 表示一个请求上传多个文件/图片后的返回值。<br/>示例一：`{ status: 'fail', error: '上传失败', response }`。<br/>示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。<br/> 示例三：`{ status: 'success', files: [{ url: 'https://xxx.png', name: 'xxx.png' }]}`
    */
   requestMethod?: (files: UploadFile | UploadFile[]) => Promise<RequestMethodResponse>;
   /**
-   * 图片文件大小限制，单位 KB。可选单位有：`'B' | 'KB' | 'MB' | 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`
+   * 图片文件大小限制，默认单位 KB。可选单位有：`'B' | 'KB' | 'MB' | 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`
    */
   sizeLimit?: number | SizeLimitObj;
   /**
-   * 触发上传的内容
-   */
-  trigger?: string | TNode<TriggerContext>;
-  /**
-   * 是否显示为模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传
+   * 是否在请求时间超过 300ms 后显示模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传。
    * @default true
    */
   useMockProgress?: boolean;
@@ -123,23 +108,19 @@ export interface TdUploadProps {
    */
   withCredentials?: boolean;
   /**
-   * 点击「取消上传」时触发
+   * 已上传文件列表发生变化时触发，`trigger` 表示触发本次的来源
    */
-  onCancelUpload?: () => void;
+  onChange?: (value: Array<T>, context: UploadChangeContext) => void;
   /**
-   * 已上传文件列表发生变化时触发
+   * 上传失败后触发。`response` 指接口响应结果，`response.error` 会作为错误文本提醒。如果希望判定为上传失败，但接口响应数据不包含 `error` 字段，可以使用 `formatResponse` 格式化 `response` 数据结构。如果是多文件多请求上传场景，请到事件 `onOneFileFail` 中查看 `response`
    */
-  onChange?: (value: Array<UploadFile>, context: UploadChangeContext) => void;
+  onFail?: (options: UploadFailContext) => void;
   /**
-   * 上传失败后触发
+   * 点击图片预览时触发，文件没有预览
    */
-  onFail?: (options: { e: ProgressEvent; file: UploadFile }) => void;
+  onPreview?: (options: { file: UploadFile; index: number; e: MouseEvent }) => void;
   /**
-   * 点击预览时触发
-   */
-  onPreview?: (options: { file: UploadFile; e: MouseEvent }) => void;
-  /**
-   * 上传进度变化时触发，真实进度和模拟进度都会触发。type 值为 real 表示真实上传进度，type 值为 mock 表示模拟上传进度
+   * 上传进度变化时触发，真实进度和模拟进度都会触发。<br/>⚠️ 原始上传请求，小文件的上传进度只有 0 和 100，故而不会触发 `progress` 事件；只有大文件才有真实的中间进度。如果你希望很小的文件也显示上传进度，保证 `useMockProgress=true` 的情况下，设置 `mockProgressDuration` 为更小的值。<br/>参数 `options.type=real` 表示真实上传进度，`options.type=mock` 表示模拟上传进度
    */
   onProgress?: (options: ProgressContext) => void;
   /**
@@ -147,60 +128,65 @@ export interface TdUploadProps {
    */
   onRemove?: (context: UploadRemoveContext) => void;
   /**
-   * 文件选择后，上传开始前，触发
+   * 选择文件或图片之后，上传之前，触发该事件
    */
-  onSelectChange?: (files: Array<UploadFile>) => void;
+  onSelectChange?: (files: File[], context: UploadSelectChangeContext) => void;
   /**
-   * 上传成功后触发，`context.currentFiles` 表示当次请求上传的文件，`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br />⚠️ `context.file` 请勿使用
+   * 上传成功后触发。<br/>`context.currentFiles` 表示当次请求上传的文件（无论成功或失败），`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br/>`context.results` 表示单次选择全部文件上传成功后的响应结果，可以在这个字段存在时提醒用户上传成功或失败。<br />
    */
   onSuccess?: (context: SuccessContext) => void;
-}
-
-export interface UploadFile {
   /**
-   * 源文件
+   * 文件上传校验结束事件，文件数量超出、文件大小超出限制、文件同名、`beforeAllFilesUpload` 返回值为假、`beforeUpload` 返回值为假等场景会触发。<br/>注意：如果设置允许上传同名文件，即 `allowUploadDuplicateFile=true`，则不会因为文件重名触发该事件。<br/>结合 `status` 和 `tips` 可以在组件中呈现不同类型的错误（或告警）提示
    */
-  fileRaw: File;
+  onValidate?: (context: { type: UploadValidateType; files: UploadFile[] }) => void;
+}
+
+export interface UploadFile extends PlainObject {
   /**
    * 上一次变更的时间
    */
-  lastModified: number;
+  lastModified?: number;
   /**
    * 文件名称
    * @default ''
    */
-  name: string;
+  name?: string;
   /**
    * 下载进度
    */
-  percent: number;
+  percent?: number;
   /**
    * 原始文件对象
    */
-  raw: File;
+  raw?: File;
   /**
-   * 上传接口返回的数据
+   * 上传接口返回的数据。`response.error` 存在时会判断此次上传失败，并显示错误文本信息；`response.url` 会作为文件上传成功后的地址，并使用该地址显示图片
    */
-  response: object;
+  response?: { [key: string]: any };
   /**
    * 文件大小
    */
-  size: number;
+  size?: number;
   /**
    * 文件上传状态：上传成功，上传失败，上传中，等待上传
    * @default ''
    */
-  status: 'success' | 'fail' | 'progress' | 'waiting';
+  status?: 'success' | 'fail' | 'progress' | 'waiting';
   /**
    * 文件类型
    * @default ''
    */
-  type: string;
+  type?: string;
+  /**
+   * 上传时间
+   * @default ''
+   */
+  uploadTime?: string;
   /**
    * 文件上传成功后的下载/访问地址
    * @default ''
    */
-  url: string;
+  url?: string;
 }
 
 export type ResponseType = { error?: string; url?: string } & Record<string, any>;
@@ -213,7 +199,7 @@ export interface FormatResponseContext {
 export interface RequestMethodResponse {
   status: 'success' | 'fail';
   error?: string;
-  response: { url?: string; [key: string]: any };
+  response: { url?: string; files?: UploadFile[]; [key: string]: any };
 }
 
 export interface SizeLimitObj {
@@ -226,24 +212,33 @@ export type SizeUnitArray = ['B', 'KB', 'MB', 'GB'];
 
 export type SizeUnit = SizeUnitArray[number];
 
-export interface TriggerContext {
-  dragActive?: boolean;
-  uploadingFile?: UploadFile | Array<UploadFile>;
-}
-
 export interface UploadChangeContext {
   e?: MouseEvent | ProgressEvent;
   response?: any;
-  trigger: string;
+  trigger: UploadChangeTrigger;
   index?: number;
   file?: UploadFile;
+  files?: UploadFile[];
 }
 
-export interface ProgressContext {
+export type UploadChangeTrigger = 'add' | 'remove' | 'abort' | 'progress-success' | 'progress' | 'progress-fail';
+
+export interface UploadFailContext {
   e?: ProgressEvent;
+  failedFiles: UploadFile[];
+  currentFiles: UploadFile[];
+  response?: any;
   file: UploadFile;
+  XMLHttpRequest?: XMLHttpRequest;
+}
+
+export interface ProgressContext {
+  e?: ProgressEvent;
+  file?: UploadFile;
+  currentFiles: UploadFile[];
   percent: number;
   type: UploadProgressType;
+  XMLHttpRequest?: XMLHttpRequest;
 }
 
 export type UploadProgressType = 'real' | 'mock';
@@ -254,9 +249,23 @@ export interface UploadRemoveContext {
   e: MouseEvent;
 }
 
+export interface UploadSelectChangeContext {
+  currentSelectedFiles: UploadFile[];
+}
+
 export interface SuccessContext {
   e?: ProgressEvent;
   file?: UploadFile;
   fileList?: UploadFile[];
-  response: any;
+  currentFiles?: UploadFile[];
+  response?: any;
+  results?: SuccessContext[];
+  XMLHttpRequest?: XMLHttpRequest;
 }
+
+export type UploadValidateType =
+  | 'FILE_OVER_SIZE_LIMIT'
+  | 'FILES_OVER_LENGTH_LIMIT'
+  | 'FILTER_FILE_SAME_NAME'
+  | 'BEFORE_ALL_FILES_UPLOAD'
+  | 'CUSTOM_BEFORE_UPLOAD';
diff --git a/src/upload/upload.en-US.md b/src/upload/upload.en-US.md
new file mode 100644
index 00000000..ad661684
--- /dev/null
+++ b/src/upload/upload.en-US.md
@@ -0,0 +1,66 @@
+:: BASE_DOC ::
+
+## API
+### Upload Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+accept | String | - | \- | N
+action | String | - | upload action url | N
+allowUploadDuplicateFile | Boolean | false | \- | N
+autoUpload | Boolean | true | \- | N
+beforeUpload | Function | - | Typescript：`(file: UploadFile) => boolean \| Promise<boolean>` | N
+data | Object | - | Typescript：`Record<string, any> \| ((files: UploadFile[]) => Record<string, any>)` | N
+disabled | Boolean | - | \- | N
+fileListDisplay | Slot / Function | - | Typescript：`TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+files | Array | [] | `v-model:files` is supported。Typescript：`Array<T>` | N
+defaultFiles | Array | [] | uncontrolled property。Typescript：`Array<T>` | N
+format | Function | - | Typescript：`(file: File) => UploadFile` | N
+formatRequest | Function | - | Typescript：`(requestData: { [key: string]: any }) => { [key: string]: any }` | N
+formatResponse | Function | - | Typescript：`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record<string, any>` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+headers | Object | - | Typescript：`{[key: string]: string}` | N
+imageProps | Object | - | Typescript：`ImageProps`，[Image API Documents](./image?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+max | Number | 0 | \- | N
+method | String | POST | options：POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch | N
+multiple | Boolean | false | \- | N
+requestMethod | Function | - | Typescript：`(files: UploadFile \| UploadFile[]) => Promise<RequestMethodResponse>` `interface RequestMethodResponse { status: 'success' \| 'fail'; error?: string; response: { url?: string; files?: UploadFile[]; [key: string]: any } }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+sizeLimit | Number / Object | - | Typescript：`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+useMockProgress | Boolean | true | \- | N
+withCredentials | Boolean | false | \- | N
+onChange | Function |  | Typescript：`(value: Array<T>, context: UploadChangeContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`<br/><br/>`type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`<br/> | N
+onFail | Function |  | Typescript：`(options: UploadFailContext) => void`<br/>`response.error` used for error tips, `formatResponse` can format `response`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadFailContext { e?: ProgressEvent; failedFiles: UploadFile[]; currentFiles: UploadFile[]; response?: any; file: UploadFile; XMLHttpRequest?: XMLHttpRequest}`<br/> | N
+onPreview | Function |  | Typescript：`(options: { file: UploadFile; index: number; e: MouseEvent }) => void`<br/> | N
+onProgress | Function |  | Typescript：`(options: ProgressContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
+onRemove | Function |  | Typescript：`(context: UploadRemoveContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/> | N
+onSelectChange | Function |  | Typescript：`(files: File[], context: UploadSelectChangeContext) => void`<br/>trigger after file choose and before upload。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/> | N
+onSuccess | Function |  | Typescript：`(context: SuccessContext) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[]; XMLHttpRequest?: XMLHttpRequest }`<br/> | N
+onValidate | Function |  | Typescript：`(context: { type: UploadValidateType, files: UploadFile[] }) => void`<br/>trigger on length over limit, or trigger on file size over limit。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`type UploadValidateType = 'FILE_OVER_SIZE_LIMIT' \| 'FILES_OVER_LENGTH_LIMIT' \| 'FILTER_FILE_SAME_NAME' \| 'BEFORE_ALL_FILES_UPLOAD' \| 'CUSTOM_BEFORE_UPLOAD'`<br/> | N
+
+### Upload Events
+
+name | params | description
+-- | -- | --
+change | `(value: Array<T>, context: UploadChangeContext)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`<br/><br/>`type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`<br/>
+fail | `(options: UploadFailContext)` | `response.error` used for error tips, `formatResponse` can format `response`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadFailContext { e?: ProgressEvent; failedFiles: UploadFile[]; currentFiles: UploadFile[]; response?: any; file: UploadFile; XMLHttpRequest?: XMLHttpRequest}`<br/>
+preview | `(options: { file: UploadFile; index: number; e: MouseEvent })` | \-
+progress | `(options: ProgressContext)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/>
+remove | `(context: UploadRemoveContext)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/>
+select-change | `(files: File[], context: UploadSelectChangeContext)` | trigger after file choose and before upload。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/>
+success | `(context: SuccessContext)` | [see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[]; XMLHttpRequest?: XMLHttpRequest }`<br/>
+validate | `(context: { type: UploadValidateType, files: UploadFile[] })` | trigger on length over limit, or trigger on file size over limit。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`type UploadValidateType = 'FILE_OVER_SIZE_LIMIT' \| 'FILES_OVER_LENGTH_LIMIT' \| 'FILTER_FILE_SAME_NAME' \| 'BEFORE_ALL_FILES_UPLOAD' \| 'CUSTOM_BEFORE_UPLOAD'`<br/>
+
+### UploadFile
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+lastModified | Number | - | \- | N
+name | String | - | \- | N
+percent | Number | - | \- | N
+raw | Object | - | Typescript：`File` | N
+response | Object | - | Typescript：`{ [key: string]: any }` | N
+size | Number | - | \- | N
+status | String | - | Typescript：` 'success' \| 'fail' \| 'progress' \| 'waiting'` | N
+type | String | - | \- | N
+uploadTime | String | - | upload time | N
+url | String | - | \- | N
+`PlainObject` | \- | - | `PlainObject` is not an attribute of UploadFile，it means you can add and attributes to UploadFile, `type PlainObject = {[key: string]: any}`' | N
diff --git a/src/upload/upload.md b/src/upload/upload.md
index 28dd3275..9bfce05e 100644
--- a/src/upload/upload.md
+++ b/src/upload/upload.md
@@ -6,61 +6,61 @@
 名称 | 类型 | 默认值 | 说明 | 必传
 -- | -- | -- | -- | --
 accept | String | - | 接受上传的文件类型，[查看 W3C示例](https://www.w3schools.com/tags/att_input_accept.asp)，[查看 MDN 示例](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file) | N
-action | String | - | 上传接口 | N
+action | String | - | 上传接口。设接口响应数据为字段 `response`，那么 `response.error` 存在时会判断此次上传失败，并显示错误文本信息；`response.url` 会作为文件上传成功后的地址，并使用该地址显示图片或文件 | N
 allowUploadDuplicateFile | Boolean | false | 是否允许重复上传相同文件名的文件 | N
-autoUpload | Boolean | true | 是否选取文件后自动上传 | N
-beforeUpload | Function | - | 上传文件之前的钩子，参数为上传的文件，返回值决定是否上传。TS 类型：`(file: File | UploadFile) => boolean | Promise<boolean>` | N
-data | Object | - | 上传文件时所需的额外数据。TS 类型：`Record<string, any> | ((file: File) => Record<string, any>)` | N
-deleteBtn | String / Slot / Function | - | 删除图标。值为空，使用默认图标渲染；值为 slot 则表示使用插槽渲染；其他值无效。。TS 类型：`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-disabled | Boolean | false | 是否禁用 | N
-fileListDisplay | Slot / Function | - | 【开发中】用于完全自定义文件列表内容。TS 类型：`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-files | Array | - | 已上传文件列表。支持语法糖 `v-model` 或 `v-model:files`。TS 类型：`Array<UploadFile>` | N
-defaultFiles | Array | - | 已上传文件列表。非受控属性。TS 类型：`Array<UploadFile>` | N
-format | Function | - | 文件上传前转换文件数据。TS 类型：`(file: File) => UploadFile` | N
-formatResponse | Function | - | 用于格式化文件上传后的响应数据。error 用于显示错误提示，如果 error 值为真，组件会判定为上传失败；url 用于上传文件/图片地址。。TS 类型：`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record<string, any>` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
-gridConfig | Object | - | upload组件每行上传图片列数以及图片的宽度和高度。TS 类型：`{column?: number;width?: number;height?: number;}` | N
-headers | Object | - | 设置上传的请求头部。TS 类型：`{[key: string]: string}` | N
+autoUpload | Boolean | true | 是否在选择文件后自动发起请求上传文件 | N
+beforeUpload | Function | - | 如果是自动上传模式 `autoUpload=true`，表示单个文件上传之前的钩子函数，若函数返回值为 `false` 则表示不上传当前文件。<br/>如果是非自动上传模式 `autoUpload=false`，函数返回值为 `false` 时表示从上传文件中剔除当前文件。TS 类型：`(file: UploadFile) => boolean \| Promise<boolean>` | N
+data | Object | - | 上传请求所需的额外字段，默认字段有 `file`，表示文件信息。可以添加额外的文件名字段，如：`{file_name: "custom-file-name.txt"}`。`autoUpload=true` 时有效。也可以使用 `formatRequest` 完全自定义上传请求的字段。TS 类型：`Record<string, any> \| ((files: UploadFile[]) => Record<string, any>)` | N
+disabled | Boolean | - | 是否禁用 | N
+fileListDisplay | Slot / Function | - | 【开发中】用于完全自定义文件列表内容。TS 类型：`TNode<{ files: UploadFile[]; dragEvents?: UploadDisplayDragEvents }>`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+files | Array | [] | 已上传文件列表，同 `value`。TS 类型：`UploadFile`。支持语法糖 `v-model:files`。TS 类型：`Array<T>` | N
+defaultFiles | Array | [] | 已上传文件列表，同 `value`。TS 类型：`UploadFile`。非受控属性。TS 类型：`Array<T>` | N
+format | Function | - | 转换文件 `UploadFile` 的数据结构，可新增或修改 `UploadFile` 的属性，注意不能删除 `UploadFile` 属性。`action` 存在时有效。TS 类型：`(file: File) => UploadFile` | N
+formatRequest | Function | - | 用于新增或修改文件上传请求参数。`action` 存在时有效。一个请求上传一个文件时，默认请求字段有 `file`；<br/>一个请求上传多个文件时，默认字段有 `file[0]/file[1]/file[2]/.../length`，其中 `length` 表示本次上传的文件数量。<br/>⚠️非常注意，此处的 `file[0]/file[1]` 仅仅是一个字段名，并非表示 `file` 是一个数组，接口获取字段时注意区分。<br/>可以使用 `name` 定义 `file` 字段的别名，也可以使用 `formatRequest` 自定义任意字段。TS 类型：`(requestData: { [key: string]: any }) => { [key: string]: any }` | N
+formatResponse | Function | - | 用于格式化文件上传后的接口响应数据，`response` 便是接口响应的原始数据。`action` 存在时有效。<br/> 此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒，如果存在会判定为本次上传失败。<br/> 此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接。TS 类型：`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record<string, any>` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+headers | Object | - | 设置上传的请求头部，`action` 存在时有效。TS 类型：`{[key: string]: string}` | N
 imageProps | Object | - | 透传 Image 组件全部属性。TS 类型：`ImageProps`，[Image API Documents](./image?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
 max | Number | 0 | 用于控制文件上传数量，值为 0 则不限制 | N
 method | String | POST | HTTP 请求类型。可选项：POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch | N
-multiple | Boolean | false | 是否支持多选文件 | N
-requestMethod | Function | - | 自定义上传方法。返回值 status 表示上传成功或失败，error 表示上传失败的原因，response 表示请求上传成功后的返回数据，response.url 表示上传成功后的图片地址。示例一：`{ status: 'fail', error: '上传失败', response }`。示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。TS 类型：`(files: UploadFile | UploadFile[]) => Promise<RequestMethodResponse>` `interface RequestMethodResponse { status: 'success' | 'fail'; error?: string; response: { url?: string; [key: string]: any } }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
-sizeLimit | Number / Object | - | 图片文件大小限制，单位 KB。可选单位有：`'B' | 'KB' | 'MB' | 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`。TS 类型：`number | SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
-trigger | String / Slot / Function | - | 触发上传的内容。TS 类型：`string | TNode<TriggerContext>` `interface TriggerContext { dragActive?: boolean; uploadingFile?: UploadFile | Array<UploadFile> }`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
-useMockProgress | Boolean | true | 是否显示为模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传 | N
+multiple | Boolean | false | 支持多文件上传 | N
+requestMethod | Function | - | 自定义上传方法。返回值 `status` 表示上传成功或失败；`error` 或 `response.error` 表示上传失败的原因；<br/>`response` 表示请求上传成功后的返回数据，`response.url` 表示上传成功后的图片/文件地址，`response.files` 表示一个请求上传多个文件/图片后的返回值。<br/>示例一：`{ status: 'fail', error: '上传失败', response }`。<br/>示例二：`{ status: 'success', response: { url: 'https://tdesign.gtimg.com/site/avatar.jpg' } }`。<br/> 示例三：`{ status: 'success', files: [{ url: 'https://xxx.png', name: 'xxx.png' }]}`。TS 类型：`(files: UploadFile \| UploadFile[]) => Promise<RequestMethodResponse>` `interface RequestMethodResponse { status: 'success' \| 'fail'; error?: string; response: { url?: string; files?: UploadFile[]; [key: string]: any } }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+sizeLimit | Number / Object | - | 图片文件大小限制，默认单位 KB。可选单位有：`'B' \| 'KB' \| 'MB' \| 'GB'`。示例一：`1000`。示例二：`{ size: 2, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' }`。TS 类型：`number \| SizeLimitObj` `interface SizeLimitObj { size: number; unit: SizeUnit ; message?: string }` `type SizeUnitArray = ['B', 'KB', 'MB', 'GB']` `type SizeUnit = SizeUnitArray[number]`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts) | N
+useMockProgress | Boolean | true | 是否在请求时间超过 300ms 后显示模拟进度。上传进度有模拟进度和真实进度两种。一般大小的文件上传，真实的上传进度只有 0 和 100，不利于交互呈现，因此组件内置模拟上传进度。真实上传进度一般用于大文件上传。 | N
 withCredentials | Boolean | false | 上传请求时是否携带 cookie | N
-onCancelUpload | Function |  | TS 类型：`() => void`<br/>点击「取消上传」时触发 | N
-onChange | Function |  | TS 类型：`(value: Array<UploadFile>, context: UploadChangeContext) => void`<br/>已上传文件列表发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent | ProgressEvent; response?: any; trigger: string; index?: number; file?: UploadFile }`<br/> | N
-onFail | Function |  | TS 类型：`(options: { e: ProgressEvent; file: UploadFile }) => void`<br/>上传失败后触发 | N
-onPreview | Function |  | TS 类型：`(options: { file: UploadFile; e: MouseEvent }) => void`<br/>点击预览时触发 | N
-onProgress | Function |  | TS 类型：`(options: ProgressContext) => void`<br/>上传进度变化时触发，真实进度和模拟进度都会触发。type 值为 real 表示真实上传进度，type 值为 mock 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file: UploadFile; percent: number; type: UploadProgressType }`<br/><br/>`type UploadProgressType = 'real' | 'mock'`<br/> | N
+onChange | Function |  | TS 类型：`(value: Array<T>, context: UploadChangeContext) => void`<br/>已上传文件列表发生变化时触发，`trigger` 表示触发本次的来源。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`<br/><br/>`type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`<br/> | N
+onFail | Function |  | TS 类型：`(options: UploadFailContext) => void`<br/>上传失败后触发。`response` 指接口响应结果，`response.error` 会作为错误文本提醒。如果希望判定为上传失败，但接口响应数据不包含 `error` 字段，可以使用 `formatResponse` 格式化 `response` 数据结构。如果是多文件多请求上传场景，请到事件 `onOneFileFail` 中查看 `response`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadFailContext { e?: ProgressEvent; failedFiles: UploadFile[]; currentFiles: UploadFile[]; response?: any; file: UploadFile; XMLHttpRequest?: XMLHttpRequest}`<br/> | N
+onPreview | Function |  | TS 类型：`(options: { file: UploadFile; index: number; e: MouseEvent }) => void`<br/>点击图片预览时触发，文件没有预览 | N
+onProgress | Function |  | TS 类型：`(options: ProgressContext) => void`<br/>上传进度变化时触发，真实进度和模拟进度都会触发。<br/>⚠️ 原始上传请求，小文件的上传进度只有 0 和 100，故而不会触发 `progress` 事件；只有大文件才有真实的中间进度。如果你希望很小的文件也显示上传进度，保证 `useMockProgress=true` 的情况下，设置 `mockProgressDuration` 为更小的值。<br/>参数 `options.type=real` 表示真实上传进度，`options.type=mock` 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/> | N
 onRemove | Function |  | TS 类型：`(context: UploadRemoveContext) => void`<br/>移除文件时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/> | N
-onSelectChange | Function |  | TS 类型：`(files: Array<UploadFile>) => void`<br/>文件选择后，上传开始前，触发 | N
-onSuccess | Function |  | TS 类型：`(context: SuccessContext) => void`<br/>上传成功后触发，`context.currentFiles` 表示当次请求上传的文件，`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br />⚠️ `context.file` 请勿使用。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; response: any }`<br/> | N
+onSelectChange | Function |  | TS 类型：`(files: File[], context: UploadSelectChangeContext) => void`<br/>选择文件或图片之后，上传之前，触发该事件。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/> | N
+onSuccess | Function |  | TS 类型：`(context: SuccessContext) => void`<br/>上传成功后触发。<br/>`context.currentFiles` 表示当次请求上传的文件（无论成功或失败），`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br/>`context.results` 表示单次选择全部文件上传成功后的响应结果，可以在这个字段存在时提醒用户上传成功或失败。<br />。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[]; XMLHttpRequest?: XMLHttpRequest }`<br/> | N
+onValidate | Function |  | TS 类型：`(context: { type: UploadValidateType, files: UploadFile[] }) => void`<br/>文件上传校验结束事件，文件数量超出、文件大小超出限制、文件同名、`beforeAllFilesUpload` 返回值为假、`beforeUpload` 返回值为假等场景会触发。<br/>注意：如果设置允许上传同名文件，即 `allowUploadDuplicateFile=true`，则不会因为文件重名触发该事件。<br/>结合 `status` 和 `tips` 可以在组件中呈现不同类型的错误（或告警）提示。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`type UploadValidateType = 'FILE_OVER_SIZE_LIMIT' \| 'FILES_OVER_LENGTH_LIMIT' \| 'FILTER_FILE_SAME_NAME' \| 'BEFORE_ALL_FILES_UPLOAD' \| 'CUSTOM_BEFORE_UPLOAD'`<br/> | N
 
 ### Upload Events
 
 名称 | 参数 | 描述
 -- | -- | --
-cancel-upload | - | 点击「取消上传」时触发
-change | `(value: Array<UploadFile>, context: UploadChangeContext)` | 已上传文件列表发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent | ProgressEvent; response?: any; trigger: string; index?: number; file?: UploadFile }`<br/>
-fail | `(options: { e: ProgressEvent; file: UploadFile })` | 上传失败后触发
-preview | `(options: { file: UploadFile; e: MouseEvent })` | 点击预览时触发
-progress | `(options: ProgressContext)` | 上传进度变化时触发，真实进度和模拟进度都会触发。type 值为 real 表示真实上传进度，type 值为 mock 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file: UploadFile; percent: number; type: UploadProgressType }`<br/><br/>`type UploadProgressType = 'real' | 'mock'`<br/>
+change | `(value: Array<T>, context: UploadChangeContext)` | 已上传文件列表发生变化时触发，`trigger` 表示触发本次的来源。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadChangeContext { e?: MouseEvent \| ProgressEvent; response?: any; trigger: UploadChangeTrigger; index?: number; file?: UploadFile; files?: UploadFile[] }`<br/><br/>`type UploadChangeTrigger = 'add' \| 'remove' \| 'abort' \| 'progress-success' \| 'progress' \| 'progress-fail'`<br/>
+fail | `(options: UploadFailContext)` | 上传失败后触发。`response` 指接口响应结果，`response.error` 会作为错误文本提醒。如果希望判定为上传失败，但接口响应数据不包含 `error` 字段，可以使用 `formatResponse` 格式化 `response` 数据结构。如果是多文件多请求上传场景，请到事件 `onOneFileFail` 中查看 `response`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadFailContext { e?: ProgressEvent; failedFiles: UploadFile[]; currentFiles: UploadFile[]; response?: any; file: UploadFile; XMLHttpRequest?: XMLHttpRequest}`<br/>
+preview | `(options: { file: UploadFile; index: number; e: MouseEvent })` | 点击图片预览时触发，文件没有预览
+progress | `(options: ProgressContext)` | 上传进度变化时触发，真实进度和模拟进度都会触发。<br/>⚠️ 原始上传请求，小文件的上传进度只有 0 和 100，故而不会触发 `progress` 事件；只有大文件才有真实的中间进度。如果你希望很小的文件也显示上传进度，保证 `useMockProgress=true` 的情况下，设置 `mockProgressDuration` 为更小的值。<br/>参数 `options.type=real` 表示真实上传进度，`options.type=mock` 表示模拟上传进度。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface ProgressContext { e?: ProgressEvent; file?: UploadFile; currentFiles: UploadFile[]; percent: number; type: UploadProgressType; XMLHttpRequest?: XMLHttpRequest }`<br/><br/>`type UploadProgressType = 'real' \| 'mock'`<br/>
 remove | `(context: UploadRemoveContext)` | 移除文件时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadRemoveContext { index?: number; file?: UploadFile; e: MouseEvent }`<br/>
-select-change | `(files: Array<UploadFile>)` | 文件选择后，上传开始前，触发
-success | `(context: SuccessContext)` | 上传成功后触发，`context.currentFiles` 表示当次请求上传的文件，`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br />⚠️ `context.file` 请勿使用。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; response: any }`<br/>
+select-change | `(files: File[], context: UploadSelectChangeContext)` | 选择文件或图片之后，上传之前，触发该事件。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[] }`<br/>
+success | `(context: SuccessContext)` | 上传成功后触发。<br/>`context.currentFiles` 表示当次请求上传的文件（无论成功或失败），`context.fileList` 表示上传成功后的文件，`context.response` 表示上传请求的返回数据。<br/>`context.results` 表示单次选择全部文件上传成功后的响应结果，可以在这个字段存在时提醒用户上传成功或失败。<br />。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`interface SuccessContext { e?: ProgressEvent; file?: UploadFile; fileList?: UploadFile[]; currentFiles?: UploadFile[]; response?: any; results?: SuccessContext[]; XMLHttpRequest?: XMLHttpRequest }`<br/>
+validate | `(context: { type: UploadValidateType, files: UploadFile[] })` | 文件上传校验结束事件，文件数量超出、文件大小超出限制、文件同名、`beforeAllFilesUpload` 返回值为假、`beforeUpload` 返回值为假等场景会触发。<br/>注意：如果设置允许上传同名文件，即 `allowUploadDuplicateFile=true`，则不会因为文件重名触发该事件。<br/>结合 `status` 和 `tips` 可以在组件中呈现不同类型的错误（或告警）提示。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/upload/type.ts)。<br/>`type UploadValidateType = 'FILE_OVER_SIZE_LIMIT' \| 'FILES_OVER_LENGTH_LIMIT' \| 'FILTER_FILE_SAME_NAME' \| 'BEFORE_ALL_FILES_UPLOAD' \| 'CUSTOM_BEFORE_UPLOAD'`<br/>
 
 ### UploadFile
 
 名称 | 类型 | 默认值 | 说明 | 必传
 -- | -- | -- | -- | --
-lastModified | Number | - | 必需。上一次变更的时间 | Y
-name | String | - | 必需。文件名称 | Y
-percent | Number | - | 必需。下载进度 | Y
-raw | Object | - | 必需。原始文件对象。TS 类型：`File` | Y
-response | Object | - | 必需。上传接口返回的数据 | Y
-size | Number | - | 必需。文件大小 | Y
-status | String | - | 必需。文件上传状态：上传成功，上传失败，上传中，等待上传。TS 类型：` 'success' | 'fail' | 'progress' | 'waiting'` | Y
-type | String | - | 必需。文件类型 | Y
-url | String | - | 必需。文件上传成功后的下载/访问地址 | Y
+lastModified | Number | - | 上一次变更的时间 | N
+name | String | - | 文件名称 | N
+percent | Number | - | 下载进度 | N
+raw | Object | - | 原始文件对象。TS 类型：`File` | N
+response | Object | - | 上传接口返回的数据。`response.error` 存在时会判断此次上传失败，并显示错误文本信息；`response.url` 会作为文件上传成功后的地址，并使用该地址显示图片。TS 类型：`{ [key: string]: any }` | N
+size | Number | - | 文件大小 | N
+status | String | - | 文件上传状态：上传成功，上传失败，上传中，等待上传。TS 类型：` 'success' \| 'fail' \| 'progress' \| 'waiting'` | N
+type | String | - | 文件类型 | N
+uploadTime | String | - | 上传时间 | N
+url | String | - | 文件上传成功后的下载/访问地址 | N
+`PlainObject` | \- | - | `PlainObject` 不是 UploadFile 中的属性，而表示 UploadFile 本身支持添加任意属性，`type PlainObject = {[key: string]: any}`' | N
diff --git a/src/upload/upload.vue b/src/upload/upload.vue
index 0fcd8ece..978aa315 100644
--- a/src/upload/upload.vue
+++ b/src/upload/upload.vue
@@ -1,42 +1,38 @@
 <template>
-  <div>
-    <ul :class="`${UPLOAD_NAME}__card`">
-      <li v-for="(file, index) in uploadedFiles" :key="index" :class="`${UPLOAD_NAME}__card-item`" :style="itemStyle">
-        <div :class="`${UPLOAD_NAME}__card-content ${UPLOAD_NAME}__card-box`" :style="itemContentStyle">
-          <div
-            key="delete-icon"
-            :class="`${UPLOAD_NAME}__card-delete-item`"
-            @click="(e) => handleRemove(e, file, index)"
-          >
-            <template v-if="deleteBtnContent">
-              <t-node :content="deleteBtnContent"></t-node>
-            </template>
-            <template v-else>
-              <close-icon class="close-icon" />
-            </template>
-          </div>
-          <img :class="`${UPLOAD_NAME}__card-image`" :src="file.url" @click="(e) => handlePreview(e, file)" />
-          <!--上传失败时，reload重试-->
-          <div v-if="file.status === 'fail'" :class="`${UPLOAD_NAME}__card-mask`">
-            <span key="refresh-icon" :class="`${UPLOAD_NAME}__card-mask-item`">
-              <refresh-icon @click="handleReload(file)" />
-            </span>
-          </div>
-        </div>
-      </li>
-      <template v-if="defaultContent">
-        <div @click="triggerUpload">
-          <t-node :content="defaultContent"></t-node>
-        </div>
-      </template>
-      <template v-else>
-        <li :class="`${UPLOAD_NAME}__card-item`" @click="triggerUpload">
-          <div :class="`${UPLOAD_NAME}__card-container ${UPLOAD_NAME}__card-box`">
-            <add-icon></add-icon>
-          </div>
-        </li>
-      </template>
-    </ul>
+  <div :class="`${name}`">
+    <div v-for="(file, index) in uploadedFiles" :key="index" :class="`${name}__item`">
+      <t-image
+        :class="`${name}__image`"
+        shape="round"
+        v-bind="imageProps"
+        :src="file.url"
+        @click="(e) => handlePreview(e, file)"
+      />
+      <div
+        v-if="file.status === 'fail' || file.status === 'progress'"
+        data-index="{{index}}"
+        :class="`${name}__progress-mask`"
+        data-file="{{file}}"
+        bind:tap="onFileClick"
+      >
+        <template v-if="file.status === 'progress'">
+          <loading-icon :class="`${name}__progress-loading`" size="24" aria-hidden />
+          <div :class="`${name}__progress-text`">{{ file.percent ? file.percent + '%' : '上传中...' }}</div>
+        </template>
+        <close-circle-icon v-else size="24" aria-hidden />
+        <div v-if="file.status === 'fail'" :class="`${name}__progress-text`">上传失败</div>
+      </div>
+      <close-icon :class="`${name}__delete-btn`" @click="({ e }) => handleRemove(e, file, index)" />
+    </div>
+    <template v-if="max === 0 || (max > 0 && uploadedFiles?.length < max)">
+      <div v-if="defaultContent" @click="triggerUpload">
+        <t-node :content="defaultContent" />
+      </div>
+      <div v-else :class="`${name}__item ${name}__item--add`" @click="triggerUpload">
+        <add-icon size="28" :class="`${name}__add-icon`" />
+      </div>
+    </template>
+
     <input
       ref="inputRef"
       :value="files"
@@ -46,24 +42,24 @@
       :accept="accept"
       @change="handleChange"
     />
-    <t-image-viewer v-model:images="images" v-model="showViewer" :initial-index="initialIndex"></t-image-viewer>
+    <t-image-viewer v-model:images="images" v-model="showViewer" :initial-index="initialIndex" />
   </div>
 </template>
 <script lang="ts">
 import { defineComponent, getCurrentInstance, ref, Ref, toRefs, computed, ComputedRef } from 'vue';
-import { AddIcon, CloseIcon, RefreshIcon } from 'tdesign-icons-vue-next';
+import { AddIcon, LoadingIcon, CloseIcon, CloseCircleIcon } from 'tdesign-icons-vue-next';
 import findIndex from 'lodash/findIndex';
-import isObject from 'lodash/isObject';
 import isFunction from 'lodash/isFunction';
 
+import TImage from '../image';
+import TImageViewer from '../image-viewer';
 import xhr from '../_common/js/upload/xhr';
 import { useDefault, useEmitEvent, renderTNode, TNode } from '../shared';
 import { TdUploadProps, UploadFile, RequestMethodResponse, SizeLimitObj } from './type';
 import { SuccessContext, InnerProgressContext } from './interface';
 import UploadProps from './props';
 import config from '../config';
-import { isOverSizeLimit } from './util';
-import TImageViewer from '../image-viewer';
+import { isOverSizeLimit } from '../_common/js/upload/utils';
 
 const { prefix } = config;
 const name = `${prefix}-upload`;
@@ -73,9 +69,11 @@ export default defineComponent({
   name,
   components: {
     AddIcon,
+    LoadingIcon,
+    CloseCircleIcon,
     TNode,
     CloseIcon,
-    RefreshIcon,
+    TImage,
     TImageViewer,
   },
   props: UploadProps,
@@ -89,6 +87,7 @@ export default defineComponent({
     'remove',
     'success',
     'select-change',
+    'validate',
   ],
   setup(props, context) {
     const emitEvent = useEmitEvent(props, context.emit);
@@ -100,11 +99,9 @@ export default defineComponent({
     );
     const internalInstance = getCurrentInstance();
     const defaultContent = computed(() => renderTNode(internalInstance, 'default'));
-    const deleteBtnContent = computed(() => renderTNode(internalInstance, 'deleteBtn'));
     const images: Ref<Array<string>> = ref([]);
     const showViewer = ref(false);
     const initialIndex = ref(0);
-    const UPLOAD_NAME = name;
     const xhrReq = ref<XMLHttpRequest | null>(null);
     // 等待上传的文件
     const toUploadFiles: Ref<Array<UploadFile>> = ref([]);
@@ -116,33 +113,8 @@ export default defineComponent({
       }
       return [];
     });
-    const errorMsg = ref('');
     const inputRef = ref<null | HTMLInputElement>(null);
 
-    const itemStyle = computed(() => {
-      const { gridConfig } = toRefs(props);
-      let column = 4;
-      if (isObject(gridConfig.value)) {
-        ({ column } = gridConfig.value as any);
-      }
-      return {
-        flexBasis: `${100 / +column}%`,
-      };
-    });
-
-    const itemContentStyle = computed(() => {
-      let width = 80;
-      let height = 80;
-      const { gridConfig } = toRefs(props);
-      if (isObject(gridConfig.value)) {
-        ({ width, height } = gridConfig.value as any);
-      }
-      return {
-        height: `${height}px`,
-        width: `${width}px`,
-      };
-    });
-
     const triggerUpload = () => {
       const input = inputRef.value as HTMLInputElement;
       if (props.disabled) return;
@@ -163,7 +135,9 @@ export default defineComponent({
 
     const handleChange = () => {
       const input = inputRef.value;
+
       if (props.disabled || !input || !input.files) return;
+
       const formatFiles = formatFileToUploadFile(input.files);
       emitEvent('select-change', [...formatFiles]);
       uploadFiles(formatFiles);
@@ -195,7 +169,11 @@ export default defineComponent({
       }
       return new Promise((resolve) => {
         if (props.sizeLimit) {
-          resolve(handleSizeLimit(file.size));
+          const isOverSizeLimit = handleSizeLimit(file.size || 0);
+          if (isOverSizeLimit) {
+            emitEvent('validate', { type: 'FILE_OVER_SIZE_LIMIT', files: [file] });
+          }
+          resolve(!handleSizeLimit(file.size || 0));
         }
         resolve(true);
       });
@@ -210,13 +188,7 @@ export default defineComponent({
       } else {
         sizeLimit = { size: 0, unit: 'KB' };
       }
-      const isOverSize = isOverSizeLimit(fileSize, sizeLimit.size, sizeLimit.unit);
-      if (isOverSize) {
-        errorMsg.value = sizeLimit.message
-          ? sizeLimit.message
-          : `TDesign Upoad Error: uploaded picture exceeds ${props.sizeLimit}${sizeLimit.unit} restrictions`;
-      }
-      return isOverSize;
+      return isOverSizeLimit(fileSize, sizeLimit.size, sizeLimit.unit);
     };
 
     const uploadFiles = (files: File[]) => {
@@ -249,8 +221,18 @@ export default defineComponent({
           const newFiles: Array<UploadFile> = toUploadFiles.value.concat();
 
           // 判断是否为重复文件条件，已选是否存在检验
-          if (props.allowUploadDuplicateFile || !toUploadFiles.value.find((file) => file.name === uploadFile.name)) {
+          if (props.allowUploadDuplicateFile) {
             newFiles.push(uploadFile);
+          } else {
+            const isDuplicated = toUploadFiles.value.some((file) => file.name === uploadFile.name);
+            if (isDuplicated) {
+              emitEvent('validate', {
+                type: 'FILTER_FILE_SAME_NAME',
+                files: [uploadFile],
+              });
+            } else {
+              newFiles.push(uploadFile);
+            }
           }
           toUploadFiles.value = newFiles;
           if (props.autoUpload) {
@@ -263,6 +245,7 @@ export default defineComponent({
     /** 模拟进度条 Mock Progress */
     const handleMockProgress = (file: UploadFile) => {
       const timer = setInterval(() => {
+        file.percent = file.percent ?? 0;
         if (file.status === 'success' || file.percent >= 99) {
           clearInterval(timer);
           return;
@@ -289,7 +272,6 @@ export default defineComponent({
     };
 
     const handleRemove = (e: MouseEvent, file: UploadFile, index: number) => {
-      errorMsg.value = '';
       const files = uploadedFiles.value.concat();
       files.splice(index, 1);
       setInnerFiles(files, { e, trigger: 'remove', index, file });
@@ -302,7 +284,6 @@ export default defineComponent({
         console.error('TDesign Upload Error: one of action and requestMethod must be exist.');
         return;
       }
-      errorMsg.value = '';
       file.status = 'progress';
       // requestMethod 为父组件定义的自定义上传方法
       if (props.requestMethod) {
@@ -313,12 +294,13 @@ export default defineComponent({
           handleMockProgress(file);
         }
         const request = xhr;
+        const data = {
+          file: file.fileRaw,
+          ...props.data,
+        };
         xhrReq.value = request({
           action: props.action,
-          data: {
-            file: file.fileRaw,
-            ...props.data,
-          },
+          data: props.formatRequest ? props.formatRequest(data) : data,
           file,
           method: props.method,
           headers: props.headers || {},
@@ -415,7 +397,7 @@ export default defineComponent({
       if (!resFormatted && props.formatResponse && isFunction(props.formatResponse)) {
         res = props.formatResponse(response, { file });
       }
-      errorMsg.value = res?.error;
+      // errorMsg.value = res?.error;
       if (
         !uploadedFiles.value.find((item) => {
           return item.name === file.name;
@@ -429,7 +411,7 @@ export default defineComponent({
 
     return {
       ...toRefs(props),
-      UPLOAD_NAME,
+      name,
       images,
       showViewer,
       initialIndex,
@@ -437,13 +419,9 @@ export default defineComponent({
       innerFiles,
       xhrReq,
       toUploadFiles,
-      errorMsg,
       inputRef,
       uploadedFiles,
-      deleteBtnContent,
       defaultContent,
-      itemStyle,
-      itemContentStyle,
       emitEvent,
       setInnerFiles,
       triggerUpload,
diff --git a/src/upload/util.ts b/src/upload/util.ts
deleted file mode 100644
index f97041de..00000000
--- a/src/upload/util.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { SizeUnit } from './type';
-/**
- * [*] 表示方法采用这种方式
- * [x] 表示方法不采用这种方式
- *
- * [x] bit      位              b     0 or 1
- * [*] byte     字节            B     8 bits
- * [x] kilobit  千位            kb    1000 bites
- * [*] kilobyte 千字节(二进制)   KB    1024 bytes
- * [x] kilobyte 千字节(十进制)   KB    1000 bytes
- * [x] Megabite 百万位          Mb    1000 kilobits
- * [*] Megabyte 兆字节(二进制)   KB    1024 kilobytes
- * [*] Megabyte 兆字节(十进制)   KB    1000 kilobytes
- * [x] Gigabit  万亿位          Gb    1000 Megabite
- * [*] Gigabyte 吉字节(二进制)   GB    1024 Megabytes
- * [x] Gigabyte 吉字节(十进制)   GB    1000 Megabytes
- */
-
-// 各个单位和 KB 的关系
-const SIZE_MAP = {
-  B: 1024,
-  KB: 1,
-  MB: 1048576, // 1024 * 1024
-  GB: 1073741824, // 1024 * 1024 * 1024
-};
-
-/**
- * 大小比较
- * @param size 文件大小
- * @param unit 计算机计量单位
- */
-export function isOverSizeLimit(fileSize: number, sizeLimit: number, unit: SizeUnit) {
-  // 以 KB 为单位进行比较
-  const units = ['B', 'KB', 'MB', 'GB'];
-  const KB_INDEX = 1;
-  let index = units.indexOf(unit);
-  if (index === -1) {
-    console.warn(`TDesign Upload Warn: \`sizeLimit.unit\` can only be one of ${units.join()}`);
-    index = KB_INDEX;
-  }
-  const num = SIZE_MAP[unit];
-  const limit = index < KB_INDEX ? sizeLimit / num : sizeLimit * num;
-  return fileSize <= limit;
-}


Test patch:
diff --git a/src/grid/__test__/__snapshots__/demo.test.jsx.snap b/src/grid/__test__/__snapshots__/demo.test.jsx.snap
index 54682f33..00189f1d 100644
--- a/src/grid/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/grid/__test__/__snapshots__/demo.test.jsx.snap
@@ -1119,20 +1119,20 @@ exports[`Grid > Grid baseVue demo works fine 1`] = `
 </div>
 `;
 
-exports[`Grid > Grid descVue demo works fine 1`] = `
+exports[`Grid > Grid borderedVue demo works fine 1`] = `
 <div
   data-v-app=""
 >
   
   <div
     class="t-grid grid-demo"
-    data-v-f7d95d20=""
+    data-v-fb92dfac=""
     style="grid-template-columns: repeat(3, 1fr);"
   >
     
     <div
-      class="t-grid-item t-grid-item--vertical"
-      data-v-f7d95d20=""
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
       style="text-align: center; flex-basis: 33.333333333333336%;"
     >
       <div
@@ -1194,8 +1194,8 @@ exports[`Grid > Grid descVue demo works fine 1`] = `
       </div>
     </div>
     <div
-      class="t-grid-item t-grid-item--vertical"
-      data-v-f7d95d20=""
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
       style="text-align: center; flex-basis: 33.333333333333336%;"
     >
       <div
@@ -1257,8 +1257,197 @@ exports[`Grid > Grid descVue demo works fine 1`] = `
       </div>
     </div>
     <div
-      class="t-grid-item t-grid-item--vertical"
-      data-v-f7d95d20=""
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题最多六字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述最多六字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical t-grid-item--bordered"
+      data-v-fb92dfac=""
       style="text-align: center; flex-basis: 33.333333333333336%;"
     >
       <div
@@ -1323,13 +1512,13 @@ exports[`Grid > Grid descVue demo works fine 1`] = `
   </div>
   <div
     class="t-grid grid-demo"
-    data-v-f7d95d20=""
+    data-v-fb92dfac=""
     style="grid-template-columns: repeat(2, 1fr);"
   >
     
     <div
-      class="t-grid-item t-grid-item--horizontal"
-      data-v-f7d95d20=""
+      class="t-grid-item t-grid-item--horizontal t-grid-item--bordered"
+      data-v-fb92dfac=""
       style="text-align: center; flex-basis: 50%;"
     >
       <div
@@ -1391,8 +1580,8 @@ exports[`Grid > Grid descVue demo works fine 1`] = `
       </div>
     </div>
     <div
-      class="t-grid-item t-grid-item--horizontal"
-      data-v-f7d95d20=""
+      class="t-grid-item t-grid-item--horizontal t-grid-item--bordered"
+      data-v-fb92dfac=""
       style="text-align: center; flex-basis: 50%;"
     >
       <div
@@ -1459,192 +1648,1119 @@ exports[`Grid > Grid descVue demo works fine 1`] = `
 </div>
 `;
 
-exports[`Grid > Grid mobileVue demo works fine 1`] = `
+exports[`Grid > Grid cardVue demo works fine 1`] = `
 <div
-  class="tdesign-mobile-demo"
+  data-v-app=""
 >
-  <h1
-    class="title"
-  >
-    Grid 宫格
-  </h1>
-  <p
-    class="summary"
-  >
-    用于功能入口布局，将页面或特定区域切分成若干等大的区块，形成若干功能入口。
-  </p>
+  
   <div
-    class="tdesign-mobile-demo-block"
+    class="t-grid t-grid--card grid-demo"
+    data-v-46f2766f=""
+    style="grid-template-columns: repeat(4, 1fr);"
   >
+    
     <div
-      class="tdesign-mobile-demo-block__header"
-    >
-      <h2
-        class="tdesign-mobile-demo-block__title"
-      >
-        01 组件类型
-      </h2>
-      <p
-        class="tdesign-mobile-demo-block__summary"
-      >
-        基础宫格
-      </p>
-    </div>
-    <div
-      class="tdesign-mobile-demo-block__slot"
+      class="t-grid-item t-grid-item--vertical"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 25%;"
     >
-      
-      
       <div
-        class="t-grid grid-demo"
-        data-v-3e578ca0=""
-        style="grid-template-columns: repeat(5, 1fr);"
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
       >
-        
         <div
-          class="t-grid-item t-grid-item--vertical"
-          data-v-3e578ca0=""
-          style="text-align: center; flex-basis: 20%;"
+          class="t-image__mask"
         >
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+            class="t-loading"
+            style="font-size: 20px;"
           >
+            
             <div
-              class="t-image__mask"
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
             >
               <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
               />
-            </picture>
-          </div>
-          <div
-            class="t-grid-item__content t-grid-item__content--vertical"
-          >
-            <div
-              class="t-grid-item__title t-grid-item__title--small"
-            >
-              标题文字
-            </div>
-            <div
-              class="t-grid-item__description t-grid-item__description--vertical"
-            >
-              <!---->
             </div>
+            
+            <!--v-if-->
+            <!---->
           </div>
         </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--middle"
+        >
+          标题文字
+        </div>
         <div
-          class="t-grid-item t-grid-item--vertical"
-          data-v-3e578ca0=""
-          style="text-align: center; flex-basis: 20%;"
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 25%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+      >
+        <div
+          class="t-image__mask"
         >
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+            class="t-loading"
+            style="font-size: 20px;"
           >
+            
             <div
-              class="t-image__mask"
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
             >
               <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
               />
-            </picture>
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
           </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--middle"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 25%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+      >
+        <div
+          class="t-image__mask"
+        >
           <div
-            class="t-grid-item__content t-grid-item__content--vertical"
+            class="t-loading"
+            style="font-size: 20px;"
           >
+            
             <div
-              class="t-grid-item__title t-grid-item__title--small"
-            >
-              标题文字
-            </div>
-            <div
-              class="t-grid-item__description t-grid-item__description--vertical"
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
             >
-              <!---->
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
             </div>
+            
+            <!--v-if-->
+            <!---->
           </div>
         </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
         <div
-          class="t-grid-item t-grid-item--vertical"
-          data-v-3e578ca0=""
-          style="text-align: center; flex-basis: 20%;"
+          class="t-grid-item__title t-grid-item__title--middle"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 25%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+      >
+        <div
+          class="t-image__mask"
         >
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+            class="t-loading"
+            style="font-size: 20px;"
           >
+            
             <div
-              class="t-image__mask"
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
             >
               <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--middle"
+        >
+          最多五个字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述最多六字
+        </div>
+      </div>
+    </div>
+    
+  </div>
+  <div
+    class="t-grid t-grid--card grid-demo"
+    data-v-46f2766f=""
+    style="grid-template-columns: repeat(2, 1fr);"
+  >
+    
+    <div
+      class="t-grid-item t-grid-item--horizontal"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 50%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--horizontal"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--horizontal"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--horizontal"
+      data-v-46f2766f=""
+      style="text-align: center; flex-basis: 50%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--horizontal"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--horizontal"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    
+  </div>
+  
+</div>
+`;
+
+exports[`Grid > Grid descVue demo works fine 1`] = `
+<div
+  data-v-app=""
+>
+  
+  <div
+    class="t-grid grid-demo"
+    data-v-f7d95d20=""
+    style="grid-template-columns: repeat(3, 1fr);"
+  >
+    
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-f7d95d20=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-f7d95d20=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--vertical"
+      data-v-f7d95d20=""
+      style="text-align: center; flex-basis: 33.333333333333336%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--vertical"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题最多六字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--vertical"
+        >
+          描述最多六字
+        </div>
+      </div>
+    </div>
+    
+  </div>
+  <div
+    class="t-grid grid-demo"
+    data-v-f7d95d20=""
+    style="grid-template-columns: repeat(2, 1fr);"
+  >
+    
+    <div
+      class="t-grid-item t-grid-item--horizontal"
+      data-v-f7d95d20=""
+      style="text-align: center; flex-basis: 50%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--horizontal"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--horizontal"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    <div
+      class="t-grid-item t-grid-item--horizontal"
+      data-v-f7d95d20=""
+      style="text-align: center; flex-basis: 50%;"
+    >
+      <div
+        class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <div
+        class="t-grid-item__content t-grid-item__content--horizontal"
+      >
+        <div
+          class="t-grid-item__title t-grid-item__title--large"
+        >
+          标题文字
+        </div>
+        <div
+          class="t-grid-item__description t-grid-item__description--horizontal"
+        >
+          描述文字
+        </div>
+      </div>
+    </div>
+    
+  </div>
+  
+</div>
+`;
+
+exports[`Grid > Grid iconVue demo works fine 1`] = `
+<div
+  class="t-grid grid-demo"
+  data-v-1b745b58=""
+  style="grid-template-columns: repeat(4, 1fr);"
+>
+  
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-1b745b58=""
+    style="text-align: center; flex-basis: 25%;"
+  >
+    
+    <div
+      class="icon-wrapper"
+      data-v-1b745b58=""
+    >
+      <svg
+        class="t-icon t-icon-share"
+        data-v-1b745b58=""
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M9.93 5.36a2.31 2.31 0 004.02-1.57 2.32 2.32 0 10-4.52.7L6.07 6.45a2.31 2.31 0 00-4.02 1.58A2.32 2.32 0 006.07 9.6l3.36 1.96a2.32 2.32 0 10.5-.87L6.57 8.73a2.32 2.32 0 000-1.41l3.36-1.96zm1.7-2.9a1.32 1.32 0 110 2.64 1.32 1.32 0 010-2.63zM5.5 7.35a.5.5 0 00.03.05 1.31 1.31 0 01-.03 1.33 1.32 1.32 0 110-1.38zm4.83 4.93c0-.22.05-.43.14-.6a.52.52 0 00.07-.13 1.32 1.32 0 11-.21.73z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--middle"
+      >
+        分享
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-1b745b58=""
+    style="text-align: center; flex-basis: 25%;"
+  >
+    
+    <div
+      class="icon-wrapper"
+      data-v-1b745b58=""
+    >
+      <svg
+        class="t-icon t-icon-star"
+        data-v-1b745b58=""
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M9.54 6.38L8 3.26 6.46 6.38l-3.44.5L5.5 9.31l-.59 3.43L8 11.12l3.08 1.62-.59-3.43L13 6.88l-3.45-.5zm5-.29a.3.3 0 01.16.52l-3.13 3.05.74 4.3a.3.3 0 01-.44.32L8 12.25l-3.87 2.03a.3.3 0 01-.43-.31l.73-4.31L1.3 6.6a.3.3 0 01.17-.52l4.33-.62 1.93-3.92a.3.3 0 01.54 0l1.94 3.92 4.32.62z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--middle"
+      >
+        收藏
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-1b745b58=""
+    style="text-align: center; flex-basis: 25%;"
+  >
+    
+    <div
+      class="icon-wrapper"
+      data-v-1b745b58=""
+    >
+      <svg
+        class="t-icon t-icon-download"
+        data-v-1b745b58=""
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M12.26 5.81L8.5 9.58V.5h-1v9.08L3.74 5.8l-.71.71 4.62 4.62c.2.2.5.2.7 0l4.62-4.62-.7-.7z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+        <path
+          d="M2 11v2a1 1 0 001 1h10a1 1 0 001-1v-2h-1v2H3v-2H2z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--middle"
+      >
+        保存
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-1b745b58=""
+    style="text-align: center; flex-basis: 25%;"
+  >
+    
+    <div
+      class="icon-wrapper"
+      data-v-1b745b58=""
+    >
+      <svg
+        class="t-icon t-icon-edit-1"
+        data-v-1b745b58=""
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <g
+          fill="currentColor"
+          fill-opacity="0.9"
+          opacity="0.9"
+        >
+          <path
+            d="M14.13 4.95L10.9 1.71l.7-.71 3.25 3.24-.7.71zM5.97 13.11l-3.61.72a.3.3 0 01-.35-.35l.72-3.61 7.3-7.3 3.24 3.24-7.3 7.3zm5.89-7.3l-1.83-1.83-6.38 6.38-.46 2.29 2.29-.46 6.38-6.38zM15 11h-4v1h4v-1zM15 13H8.5v1H15v-1z"
+          />
+        </g>
+      </svg>
+    </div>
+    
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--middle"
+      >
+        编辑
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  
+</div>
+`;
+
+exports[`Grid > Grid mobileVue demo works fine 1`] = `
+<div
+  class="tdesign-mobile-demo"
+>
+  <h1
+    class="title"
+  >
+    Grid 宫格
+  </h1>
+  <p
+    class="summary"
+  >
+    用于功能入口布局，将页面或特定区域切分成若干等大的区块，形成若干功能入口。
+  </p>
+  <div
+    class="tdesign-mobile-demo-block"
+  >
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <h2
+        class="tdesign-mobile-demo-block__title"
+      >
+        01 组件类型
+      </h2>
+      <p
+        class="tdesign-mobile-demo-block__summary"
+      >
+        基础宫格
+      </p>
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot"
+    >
+      
+      
+      <div
+        class="t-grid grid-demo"
+        data-v-3e578ca0=""
+        style="grid-template-columns: repeat(5, 1fr);"
+      >
+        
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-3e578ca0=""
+          style="text-align: center; flex-basis: 20%;"
+        >
+          <div
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+          >
+            <div
+              class="t-image__mask"
+            >
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
+              />
+            </picture>
+          </div>
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--small"
+            >
+              标题文字
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              <!---->
+            </div>
+          </div>
+        </div>
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-3e578ca0=""
+          style="text-align: center; flex-basis: 20%;"
+        >
+          <div
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+          >
+            <div
+              class="t-image__mask"
+            >
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
+              />
+            </picture>
+          </div>
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--small"
+            >
+              标题文字
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              <!---->
+            </div>
+          </div>
+        </div>
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-3e578ca0=""
+          style="text-align: center; flex-basis: 20%;"
+        >
+          <div
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--small"
+          >
+            <div
+              class="t-image__mask"
+            >
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
                   style="animation-duration: 800ms; width: 20px; height: 20px;"
                 >
                   <div
@@ -4291,131 +5407,391 @@ exports[`Grid > Grid mobileVue demo works fine 1`] = `
         </div>
         <div
           class="t-grid-item t-grid-item--vertical"
-          data-v-1b745b58=""
+          data-v-1b745b58=""
+          style="text-align: center; flex-basis: 25%;"
+        >
+          
+          <div
+            class="icon-wrapper"
+            data-v-1b745b58=""
+          >
+            <svg
+              class="t-icon t-icon-download"
+              data-v-1b745b58=""
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M12.26 5.81L8.5 9.58V.5h-1v9.08L3.74 5.8l-.71.71 4.62 4.62c.2.2.5.2.7 0l4.62-4.62-.7-.7z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+              <path
+                d="M2 11v2a1 1 0 001 1h10a1 1 0 001-1v-2h-1v2H3v-2H2z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--middle"
+            >
+              保存
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              <!---->
+            </div>
+          </div>
+        </div>
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-1b745b58=""
+          style="text-align: center; flex-basis: 25%;"
+        >
+          
+          <div
+            class="icon-wrapper"
+            data-v-1b745b58=""
+          >
+            <svg
+              class="t-icon t-icon-edit-1"
+              data-v-1b745b58=""
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <g
+                fill="currentColor"
+                fill-opacity="0.9"
+                opacity="0.9"
+              >
+                <path
+                  d="M14.13 4.95L10.9 1.71l.7-.71 3.25 3.24-.7.71zM5.97 13.11l-3.61.72a.3.3 0 01-.35-.35l.72-3.61 7.3-7.3 3.24 3.24-7.3 7.3zm5.89-7.3l-1.83-1.83-6.38 6.38-.46 2.29 2.29-.46 6.38-6.38zM15 11h-4v1h4v-1zM15 13H8.5v1H15v-1z"
+                />
+              </g>
+            </svg>
+          </div>
+          
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--middle"
+            >
+              编辑
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              <!---->
+            </div>
+          </div>
+        </div>
+        
+      </div>
+      
+    </div>
+  </div>
+  <div
+    class="tdesign-mobile-demo-block tdesign-mobile-demo-block_notitle"
+  >
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <!--v-if-->
+      <p
+        class="tdesign-mobile-demo-block__summary tdesign-mobile-demo-block_subtitle"
+      >
+        卡片宫格
+      </p>
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot"
+    >
+      
+      
+      <div
+        class="t-grid t-grid--card grid-demo"
+        data-v-46f2766f=""
+        style="grid-template-columns: repeat(4, 1fr);"
+      >
+        
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-46f2766f=""
+          style="text-align: center; flex-basis: 25%;"
+        >
+          <div
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+          >
+            <div
+              class="t-image__mask"
+            >
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
+              />
+            </picture>
+          </div>
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--middle"
+            >
+              标题文字
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              描述文字
+            </div>
+          </div>
+        </div>
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-46f2766f=""
+          style="text-align: center; flex-basis: 25%;"
+        >
+          <div
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+          >
+            <div
+              class="t-image__mask"
+            >
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
+              />
+            </picture>
+          </div>
+          <div
+            class="t-grid-item__content t-grid-item__content--vertical"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--middle"
+            >
+              标题文字
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--vertical"
+            >
+              描述文字
+            </div>
+          </div>
+        </div>
+        <div
+          class="t-grid-item t-grid-item--vertical"
+          data-v-46f2766f=""
           style="text-align: center; flex-basis: 25%;"
         >
-          
           <div
-            class="icon-wrapper"
-            data-v-1b745b58=""
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
           >
-            <svg
-              class="t-icon t-icon-download"
-              data-v-1b745b58=""
-              fill="none"
-              height="1em"
-              viewBox="0 0 16 16"
-              width="1em"
+            <div
+              class="t-image__mask"
             >
-              <path
-                d="M12.26 5.81L8.5 9.58V.5h-1v9.08L3.74 5.8l-.71.71 4.62 4.62c.2.2.5.2.7 0l4.62-4.62-.7-.7z"
-                fill="currentColor"
-                fill-opacity="0.9"
-              />
-              <path
-                d="M2 11v2a1 1 0 001 1h10a1 1 0 001-1v-2h-1v2H3v-2H2z"
-                fill="currentColor"
-                fill-opacity="0.9"
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
+              >
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
               />
-            </svg>
+            </picture>
           </div>
-          
           <div
             class="t-grid-item__content t-grid-item__content--vertical"
           >
             <div
               class="t-grid-item__title t-grid-item__title--middle"
             >
-              保存
+              标题文字
             </div>
             <div
               class="t-grid-item__description t-grid-item__description--vertical"
             >
-              <!---->
+              描述文字
             </div>
           </div>
         </div>
         <div
           class="t-grid-item t-grid-item--vertical"
-          data-v-1b745b58=""
+          data-v-46f2766f=""
           style="text-align: center; flex-basis: 25%;"
         >
-          
           <div
-            class="icon-wrapper"
-            data-v-1b745b58=""
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
           >
-            <svg
-              class="t-icon t-icon-edit-1"
-              data-v-1b745b58=""
-              fill="none"
-              height="1em"
-              viewBox="0 0 16 16"
-              width="1em"
+            <div
+              class="t-image__mask"
             >
-              <g
-                fill="currentColor"
-                fill-opacity="0.9"
-                opacity="0.9"
+              <div
+                class="t-loading"
+                style="font-size: 20px;"
               >
-                <path
-                  d="M14.13 4.95L10.9 1.71l.7-.71 3.25 3.24-.7.71zM5.97 13.11l-3.61.72a.3.3 0 01-.35-.35l.72-3.61 7.3-7.3 3.24 3.24-7.3 7.3zm5.89-7.3l-1.83-1.83-6.38 6.38-.46 2.29 2.29-.46 6.38-6.38zM15 11h-4v1h4v-1zM15 13H8.5v1H15v-1z"
-                />
-              </g>
-            </svg>
+                
+                <div
+                  class="t-loading__dots"
+                  style="animation-duration: 800ms; width: 20px; height: 20px;"
+                >
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                  />
+                  <div
+                    class="t-loading__dot"
+                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                  />
+                </div>
+                
+                <!--v-if-->
+                <!---->
+              </div>
+            </div>
+            <picture>
+              <!--v-if-->
+              <img
+                alt=""
+                class="t-image__img"
+                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+                style="object-fit: fill; object-position: center;"
+              />
+            </picture>
           </div>
-          
           <div
             class="t-grid-item__content t-grid-item__content--vertical"
           >
             <div
               class="t-grid-item__title t-grid-item__title--middle"
             >
-              编辑
+              最多五个字
             </div>
             <div
               class="t-grid-item__description t-grid-item__description--vertical"
             >
-              <!---->
+              描述最多六字
             </div>
           </div>
         </div>
         
       </div>
-      
-    </div>
-  </div>
-  <div
-    class="tdesign-mobile-demo-block tdesign-mobile-demo-block_notitle"
-  >
-    <div
-      class="tdesign-mobile-demo-block__header"
-    >
-      <!--v-if-->
-      <p
-        class="tdesign-mobile-demo-block__summary tdesign-mobile-demo-block_subtitle"
-      >
-        卡片宫格
-      </p>
-    </div>
-    <div
-      class="tdesign-mobile-demo-block__slot"
-    >
-      
-      
       <div
         class="t-grid t-grid--card grid-demo"
         data-v-46f2766f=""
-        style="grid-template-columns: repeat(4, 1fr);"
+        style="grid-template-columns: repeat(2, 1fr);"
       >
         
         <div
-          class="t-grid-item t-grid-item--vertical"
+          class="t-grid-item t-grid-item--horizontal"
           data-v-46f2766f=""
-          style="text-align: center; flex-basis: 25%;"
+          style="text-align: center; flex-basis: 50%;"
         >
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
           >
             <div
               class="t-image__mask"
@@ -4458,27 +5834,27 @@ exports[`Grid > Grid mobileVue demo works fine 1`] = `
             </picture>
           </div>
           <div
-            class="t-grid-item__content t-grid-item__content--vertical"
+            class="t-grid-item__content t-grid-item__content--horizontal"
           >
             <div
-              class="t-grid-item__title t-grid-item__title--middle"
+              class="t-grid-item__title t-grid-item__title--large"
             >
               标题文字
             </div>
             <div
-              class="t-grid-item__description t-grid-item__description--vertical"
+              class="t-grid-item__description t-grid-item__description--horizontal"
             >
               描述文字
             </div>
           </div>
         </div>
         <div
-          class="t-grid-item t-grid-item--vertical"
+          class="t-grid-item t-grid-item--horizontal"
           data-v-46f2766f=""
-          style="text-align: center; flex-basis: 25%;"
+          style="text-align: center; flex-basis: 50%;"
         >
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+            class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
           >
             <div
               class="t-image__mask"
@@ -4521,285 +5897,667 @@ exports[`Grid > Grid mobileVue demo works fine 1`] = `
             </picture>
           </div>
           <div
-            class="t-grid-item__content t-grid-item__content--vertical"
+            class="t-grid-item__content t-grid-item__content--horizontal"
+          >
+            <div
+              class="t-grid-item__title t-grid-item__title--large"
+            >
+              标题文字
+            </div>
+            <div
+              class="t-grid-item__description t-grid-item__description--horizontal"
+            >
+              描述文字
+            </div>
+          </div>
+        </div>
+        
+      </div>
+      
+      
+    </div>
+  </div>
+</div>
+`;
+
+exports[`Grid > Grid scrollVue demo works fine 1`] = `
+<div
+  class="t-grid t-grid--auto-size grid-demo"
+  data-v-7052a5ec=""
+>
+  
+  
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
+          <div
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
+          >
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
+          </div>
+          
+          <!--v-if-->
+          <!---->
+        </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
+          <div
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
+          >
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
+          </div>
+          
+          <!--v-if-->
+          <!---->
+        </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
+          <div
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-grid-item__title t-grid-item__title--middle"
-            >
-              标题文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
             <div
-              class="t-grid-item__description t-grid-item__description--vertical"
-            >
-              描述文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
         </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
         <div
-          class="t-grid-item t-grid-item--vertical"
-          data-v-46f2766f=""
-          style="text-align: center; flex-basis: 25%;"
+          class="t-loading"
+          style="font-size: 20px;"
         >
+          
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-image__mask"
-            >
-              <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
-              />
-            </picture>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
+        </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
           <div
-            class="t-grid-item__content t-grid-item__content--vertical"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-grid-item__title t-grid-item__title--middle"
-            >
-              标题文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
             <div
-              class="t-grid-item__description t-grid-item__description--vertical"
-            >
-              描述文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
         </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
         <div
-          class="t-grid-item t-grid-item--vertical"
-          data-v-46f2766f=""
-          style="text-align: center; flex-basis: 25%;"
+          class="t-loading"
+          style="font-size: 20px;"
         >
+          
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--middle"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-image__mask"
-            >
-              <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
-              />
-            </picture>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
+        </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
           <div
-            class="t-grid-item__content t-grid-item__content--vertical"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-grid-item__title t-grid-item__title--middle"
-            >
-              最多五个字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
             <div
-              class="t-grid-item__description t-grid-item__description--vertical"
-            >
-              描述最多六字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
         </div>
-        
       </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
       <div
-        class="t-grid t-grid--card grid-demo"
-        data-v-46f2766f=""
-        style="grid-template-columns: repeat(2, 1fr);"
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
       >
-        
         <div
-          class="t-grid-item t-grid-item--horizontal"
-          data-v-46f2766f=""
-          style="text-align: center; flex-basis: 50%;"
+          class="t-loading"
+          style="font-size: 20px;"
         >
+          
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-image__mask"
-            >
-              <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
-              />
-            </picture>
-          </div>
-          <div
-            class="t-grid-item__content t-grid-item__content--horizontal"
-          >
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
             <div
-              class="t-grid-item__title t-grid-item__title--large"
-            >
-              标题文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
             <div
-              class="t-grid-item__description t-grid-item__description--horizontal"
-            >
-              描述文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
         </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
         <div
-          class="t-grid-item t-grid-item--horizontal"
-          data-v-46f2766f=""
-          style="text-align: center; flex-basis: 50%;"
+          class="t-loading"
+          style="font-size: 20px;"
         >
+          
           <div
-            class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-image__mask"
-            >
-              <div
-                class="t-loading"
-                style="font-size: 20px;"
-              >
-                
-                <div
-                  class="t-loading__dots"
-                  style="animation-duration: 800ms; width: 20px; height: 20px;"
-                >
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
-                  />
-                  <div
-                    class="t-loading__dot"
-                    style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
-                  />
-                </div>
-                
-                <!--v-if-->
-                <!---->
-              </div>
-            </div>
-            <picture>
-              <!--v-if-->
-              <img
-                alt=""
-                class="t-image__img"
-                src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
-                style="object-fit: fill; object-position: center;"
-              />
-            </picture>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
+        </div>
+      </div>
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
+    </div>
+  </div>
+  <div
+    class="t-grid-item t-grid-item--vertical"
+    data-v-7052a5ec=""
+    style="text-align: center;"
+  >
+    <div
+      class="t-image t-image--round t-grid-item__image t-grid-item__image--large"
+    >
+      <div
+        class="t-image__mask"
+      >
+        <div
+          class="t-loading"
+          style="font-size: 20px;"
+        >
+          
           <div
-            class="t-grid-item__content t-grid-item__content--horizontal"
+            class="t-loading__dots"
+            style="animation-duration: 800ms; width: 20px; height: 20px;"
           >
             <div
-              class="t-grid-item__title t-grid-item__title--large"
-            >
-              标题文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0s;"
+            />
             <div
-              class="t-grid-item__description t-grid-item__description--horizontal"
-            >
-              描述文字
-            </div>
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+            />
+            <div
+              class="t-loading__dot"
+              style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+            />
           </div>
+          
+          <!--v-if-->
+          <!---->
         </div>
-        
       </div>
-      
-      
+      <picture>
+        <!--v-if-->
+        <img
+          alt=""
+          class="t-image__img"
+          src="https://tdesign.gtimg.com/miniprogram/images/example1.png"
+          style="object-fit: fill; object-position: center;"
+        />
+      </picture>
+    </div>
+    <div
+      class="t-grid-item__content t-grid-item__content--vertical"
+    >
+      <div
+        class="t-grid-item__title t-grid-item__title--large"
+      >
+        标题文字
+      </div>
+      <div
+        class="t-grid-item__description t-grid-item__description--vertical"
+      >
+        <!---->
+      </div>
     </div>
   </div>
+  
+  
 </div>
 `;
diff --git a/src/grid/__test__/demo.test.jsx b/src/grid/__test__/demo.test.jsx
index a516f0de..07e0cf0c 100644
--- a/src/grid/__test__/demo.test.jsx
+++ b/src/grid/__test__/demo.test.jsx
@@ -5,14 +5,22 @@
 import { mount } from '@vue/test-utils';
 import badgeVue from '@/grid/demos/badge.vue';
 import baseVue from '@/grid/demos/base.vue';
+import borderedVue from '@/grid/demos/bordered.vue';
+import cardVue from '@/grid/demos/card.vue';
 import descVue from '@/grid/demos/desc.vue';
+import iconVue from '@/grid/demos/icon.vue';
 import mobileVue from '@/grid/demos/mobile.vue';
+import scrollVue from '@/grid/demos/scroll.vue';
 
 const mapper = {
   badgeVue,
   baseVue,
+  borderedVue,
+  cardVue,
   descVue,
+  iconVue,
   mobileVue,
+  scrollVue,
 };
 
 describe('Grid', () => {
diff --git a/src/message/__test__/__snapshots__/demo.test.jsx.snap b/src/message/__test__/__snapshots__/demo.test.jsx.snap
index 5bf8808e..f3b73603 100644
--- a/src/message/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/message/__test__/__snapshots__/demo.test.jsx.snap
@@ -12,7 +12,7 @@ exports[`Message > Message baseVue demo works fine 1`] = `
   >
     <button
       aria-disabled="false"
-      class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+      class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
       data-v-e60c559e=""
       role="button"
     >
@@ -21,13 +21,13 @@ exports[`Message > Message baseVue demo works fine 1`] = `
         class="t-button__text"
       >
         
-        纯文字通知
+        纯文字的通知
         
       </span>
     </button>
     <button
       aria-disabled="false"
-      class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+      class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
       data-v-e60c559e=""
       role="button"
     >
@@ -36,13 +36,13 @@ exports[`Message > Message baseVue demo works fine 1`] = `
         class="t-button__text"
       >
         
-        带图标通知
+        带图标的通知
         
       </span>
     </button>
     <button
       aria-disabled="false"
-      class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+      class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
       data-v-e60c559e=""
       role="button"
     >
@@ -51,13 +51,13 @@ exports[`Message > Message baseVue demo works fine 1`] = `
         class="t-button__text"
       >
         
-        带关闭通知
+        带关闭的通知
         
       </span>
     </button>
     <button
       aria-disabled="false"
-      class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+      class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
       data-v-e60c559e=""
       role="button"
     >
@@ -66,13 +66,13 @@ exports[`Message > Message baseVue demo works fine 1`] = `
         class="t-button__text"
       >
         
-        滚动通知
+        可滚动的通知
         
       </span>
     </button>
     <button
       aria-disabled="false"
-      class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+      class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
       data-v-e60c559e=""
       role="button"
     >
@@ -81,7 +81,7 @@ exports[`Message > Message baseVue demo works fine 1`] = `
         class="t-button__text"
       >
         
-        带按钮通知
+        带按钮的通知
         
       </span>
     </button>
@@ -151,8 +151,9 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
   </h1>
   <p
     class="summary"
+    style="margin: 8px 16px 0px;"
   >
-    用于页面消息通知提示，具有成功提示、提醒、警示等功能，通常在顶部出现，可以自动消失或点击关闭
+    用于轻量级反馈或提示，不会打断用户操作。
   </p>
   <div
     class="tdesign-mobile-demo-block"
@@ -163,19 +164,18 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
       <h2
         class="tdesign-mobile-demo-block__title"
       >
-        01 类型
+        01 组件类型
       </h2>
       <p
         class="tdesign-mobile-demo-block__summary"
       >
-        弹窗内容为存文本、标题和副标题、带输入框
+        消息通知内容为文本、带操作按钮
       </p>
     </div>
     <div
       class="tdesign-mobile-demo-block__slot"
     >
       
-      <!-- &lt;functionDemo /&gt; -->
       
       <div
         class="button-demo"
@@ -184,7 +184,7 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
       >
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
           data-v-e60c559e=""
           role="button"
         >
@@ -193,13 +193,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            纯文字通知
+            纯文字的通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
           data-v-e60c559e=""
           role="button"
         >
@@ -208,13 +208,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            带图标通知
+            带图标的通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
           data-v-e60c559e=""
           role="button"
         >
@@ -223,13 +223,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            带关闭通知
+            带关闭的通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
           data-v-e60c559e=""
           role="button"
         >
@@ -238,13 +238,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            滚动通知
+            可滚动的通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
           data-v-e60c559e=""
           role="button"
         >
@@ -253,7 +253,7 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            带按钮通知
+            带按钮的通知
             
           </span>
         </button>
@@ -321,12 +321,12 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
       <h2
         class="tdesign-mobile-demo-block__title"
       >
-        02 状态
+        02 组件风格
       </h2>
       <p
         class="tdesign-mobile-demo-block__summary"
       >
-        弹窗内容为存文本、标题和副标题、带输入框
+        消息组件风格
       </p>
     </div>
     <div
@@ -335,11 +335,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
       
       <div
         class="button-demo"
+        data-v-fba28ece=""
         style="margin: 0px 16px;"
       >
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+          data-v-fba28ece=""
           role="button"
         >
           <!---->
@@ -353,7 +355,8 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+          data-v-fba28ece=""
           role="button"
         >
           <!---->
@@ -361,13 +364,14 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            警示提示通知
+            成功通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+          data-v-fba28ece=""
           role="button"
         >
           <!---->
@@ -375,13 +379,14 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            成功提示通知
+            警示通知
             
           </span>
         </button>
         <button
           aria-disabled="false"
-          class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+          class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+          data-v-fba28ece=""
           role="button"
         >
           <!---->
@@ -389,7 +394,7 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
             class="t-button__text"
           >
             
-            错误提示通知
+            错误通知
             
           </span>
         </button>
@@ -403,11 +408,13 @@ exports[`Message > Message mobileVue demo works fine 1`] = `
 exports[`Message > Message themeVue demo works fine 1`] = `
 <div
   class="button-demo"
+  data-v-fba28ece=""
   style="margin: 0px 16px;"
 >
   <button
     aria-disabled="false"
-    class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+    class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+    data-v-fba28ece=""
     role="button"
   >
     <!---->
@@ -421,7 +428,8 @@ exports[`Message > Message themeVue demo works fine 1`] = `
   </button>
   <button
     aria-disabled="false"
-    class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+    class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+    data-v-fba28ece=""
     role="button"
   >
     <!---->
@@ -429,13 +437,14 @@ exports[`Message > Message themeVue demo works fine 1`] = `
       class="t-button__text"
     >
       
-      警示提示通知
+      成功通知
       
     </span>
   </button>
   <button
     aria-disabled="false"
-    class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+    class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+    data-v-fba28ece=""
     role="button"
   >
     <!---->
@@ -443,13 +452,14 @@ exports[`Message > Message themeVue demo works fine 1`] = `
       class="t-button__text"
     >
       
-      成功提示通知
+      警示通知
       
     </span>
   </button>
   <button
     aria-disabled="false"
-    class="t-button t-size-l t-button--outline t-button--default t-button--shape-rectangle t-is-block"
+    class="t-button t-size-l t-button--outline t-button--primary t-button--shape-rectangle t-is-block"
+    data-v-fba28ece=""
     role="button"
   >
     <!---->
@@ -457,7 +467,7 @@ exports[`Message > Message themeVue demo works fine 1`] = `
       class="t-button__text"
     >
       
-      错误提示通知
+      错误通知
       
     </span>
   </button>
diff --git a/src/message/__test__/index.test.jsx b/src/message/__test__/index.test.jsx
index cb5716dd..9d864080 100644
--- a/src/message/__test__/index.test.jsx
+++ b/src/message/__test__/index.test.jsx
@@ -1,7 +1,7 @@
 import { h } from 'vue';
 import { mount } from '@vue/test-utils';
 import { describe, it, expect } from 'vitest';
-import { ref, nextTick } from 'vue';
+import { nextTick } from 'vue';
 import Message from '../message.vue';
 import { AppIcon as TIconApp } from 'tdesign-icons-vue-next';
 const prefix = 't';
@@ -17,69 +17,69 @@ describe('Message.vue', () => {
       ).toBeTruthy();
     });
 
-    it(': closeBtn is a function', () => {
-      const closeBtn = () => h(TIconApp);
-      const wrapper = mount(<Message visible closeBtn={closeBtn} />);
-      expect(wrapper.findComponent(TIconApp).exists()).toBeTruthy();
-    });
-
     it(': marquee', async () => {
-      const wrapper0 = mount(<Message visible />);
-      await nextTick();
-      expect(wrapper0.vm.scroll.marquee).toBe(false);
+      const wrapper = mount(<Message visible />);
+      expect(wrapper.vm.scroll.marquee).toBe(false);
 
-      const wrapper = mount(<Message visible marquee />);
-      await nextTick();
-      expect(wrapper.vm.scroll.marquee).toBe(true);
+      const wrapper1 = mount(<Message visible marquee />);
+      expect(wrapper1.vm.scroll.marquee).toBe(false);
 
-      const params = { loop: -1 };
-      const wrapper2 = mount(<Message visible marquee={params} />);
+      const wrapper2 = mount(<Message visible marquee={true} />);
       await nextTick();
       expect(wrapper2.vm.scroll.marquee).toBe(true);
 
-      params.loop = 0;
-      const wrapper3 = mount(<Message visible marquee={params} />);
+      const wrapper3 = mount(<Message visible marquee={{ loop: 1 }} />);
       await nextTick();
+      expect(wrapper3.vm.scroll.marquee).toBe(true);
+      wrapper3.vm.handleTransitionend();
+      expect(wrapper3.vm.scroll.loop).toBe(0);
+      wrapper3.vm.handleTransitionend();
       expect(wrapper3.vm.scroll.marquee).toBe(false);
+
+      const wrapper4 = mount(<Message visible marquee={{ loop: -1 }} />);
+      await nextTick();
+      expect(wrapper4.vm.scroll.marquee).toBe(true);
+      wrapper4.vm.handleTransitionend();
     });
-  });
 
-  describe('event', () => {
-    it('open', async () => {
+    it(': duration', () => {
+      function timer(callback) {
+        setTimeout(() => {
+          callback();
+        }, 5000);
+      }
+      vi.useFakeTimers();
       const fn = vi.fn();
-      const visible = ref(false);
-      const wrapper = mount(() => <Message v-model={visible.value} content="这是一条消息通知" onOpen={fn} />);
-      visible.value = true;
-      await nextTick();
-      expect(fn).toBeCalledTimes(1);
-      visible.value = false;
-      await nextTick();
+      timer(fn);
+      const wrapper = mount(<Message visible duration={5000} onCloseBtnClick={fn} />);
+      vi.advanceTimersByTime(5000);
       expect(fn).toBeCalledTimes(1);
     });
 
+    it(': closeBtn is a function', () => {
+      const closeBtn = () => h(TIconApp);
+      const wrapper = mount(<Message visible closeBtn={closeBtn} />);
+      expect(wrapper.findComponent(TIconApp).exists()).toBeTruthy();
+    });
+  });
+
+  describe('event', () => {
     it('close', () => {
       const fn = vi.fn();
       const wrapper = mount(() => (
-        <Message visible={true} content="这是一条带关闭的消息通知，常驻可关闭" closeBtn={true} onClose={fn} />
+        <Message visible={true} content="这是一条带关闭的消息通知，常驻可关闭" closeBtn={true} onCloseBtnClick={fn} />
       ));
       const closeBtn = wrapper.find('.t-icon-close');
       closeBtn.trigger('click');
       expect(fn).toBeCalledTimes(1);
     });
-
-    it('after-enter-leave', async () => {
-      const fn = vi.fn();
-      const wrapper = mount(() => <Message visible={true} onOpened={fn} onClosed={fn} />);
-      expect(fn).not.toBeCalled();
-      wrapper.findComponent(Message).vm.afterEnter();
-      expect(fn).toBeCalledTimes(1);
-      wrapper.findComponent(Message).vm.afterLeave();
-      expect(fn).toBeCalledTimes(2);
-    });
   });
 
   describe('slots', () => {
-    it('icon:success', () => {
+    it('icon', () => {
+      const wrapper0 = mount(() => <Message visible={true} icon={false} content="这是一条消息通知" />);
+      expect(wrapper0.find('.t-icon').exists()).toBeFalsy();
+
       const wrapper = mount(() => <Message visible={true} content="这是一条消息通知" theme={'success'} />);
       const successIcon = wrapper.find('.t-icon-check-circle-filled');
       expect(successIcon).toBeTruthy();
diff --git a/src/upload/__test__/__snapshots__/demo.test.jsx.snap b/src/upload/__test__/__snapshots__/demo.test.jsx.snap
index bd8b1e17..537c02d9 100644
--- a/src/upload/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/upload/__test__/__snapshots__/demo.test.jsx.snap
@@ -9,71 +9,33 @@ exports[`Upload > Upload baseVue demo works fine 1`] = `
     class="upload-title"
     data-v-4dac5dd5=""
   >
-    上传图片
+    单选上传
   </div>
   <div
+    class="t-upload"
     data-v-4dac5dd5=""
   >
-    <ul
-      class="t-upload__card"
+    
+    
+    
+    <div
+      class="t-upload__item t-upload__item--add"
     >
-      
-      <li
-        class="t-upload__card-item"
-        style="flex-basis: 25%;"
+      <svg
+        class="t-icon t-icon-add t-upload__add-icon"
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
       >
-        <div
-          class="t-upload__card-content t-upload__card-box"
-          style="height: 80px; width: 80px;"
-        >
-          <div
-            class="t-upload__card-delete-item"
-          >
-            <svg
-              class="t-icon t-icon-close close-icon"
-              fill="none"
-              height="1em"
-              viewBox="0 0 16 16"
-              width="1em"
-            >
-              <path
-                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
-                fill="currentColor"
-                fill-opacity="0.9"
-              />
-            </svg>
-          </div>
-          <img
-            class="t-upload__card-image"
-            src="https://tdesign.gtimg.com/site/upload1.png"
-          />
-          <!--上传失败时，reload重试-->
-          <!--v-if-->
-        </div>
-      </li>
-      
-      <li
-        class="t-upload__card-item"
-      >
-        <div
-          class="t-upload__card-container t-upload__card-box"
-        >
-          <svg
-            class="t-icon t-icon-add"
-            fill="none"
-            height="1em"
-            viewBox="0 0 16 16"
-            width="1em"
-          >
-            <path
-              d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
-              fill="currentColor"
-              fill-opacity="0.9"
-            />
-          </svg>
-        </div>
-      </li>
-    </ul>
+        <path
+          d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
     <input
       accept="image/png"
       hidden=""
@@ -121,12 +83,12 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
       <h2
         class="tdesign-mobile-demo-block__title"
       >
-        01 类型
+        01 组件类型
       </h2>
       <p
         class="tdesign-mobile-demo-block__summary"
       >
-        单选上传图片
+        单选上传
       </p>
     </div>
     <div
@@ -141,71 +103,33 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
           class="upload-title"
           data-v-4dac5dd5=""
         >
-          上传图片
+          单选上传
         </div>
         <div
+          class="t-upload"
           data-v-4dac5dd5=""
         >
-          <ul
-            class="t-upload__card"
+          
+          
+          
+          <div
+            class="t-upload__item t-upload__item--add"
           >
-            
-            <li
-              class="t-upload__card-item"
-              style="flex-basis: 25%;"
-            >
-              <div
-                class="t-upload__card-content t-upload__card-box"
-                style="height: 80px; width: 80px;"
-              >
-                <div
-                  class="t-upload__card-delete-item"
-                >
-                  <svg
-                    class="t-icon t-icon-close close-icon"
-                    fill="none"
-                    height="1em"
-                    viewBox="0 0 16 16"
-                    width="1em"
-                  >
-                    <path
-                      d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
-                      fill="currentColor"
-                      fill-opacity="0.9"
-                    />
-                  </svg>
-                </div>
-                <img
-                  class="t-upload__card-image"
-                  src="https://tdesign.gtimg.com/site/upload1.png"
-                />
-                <!--上传失败时，reload重试-->
-                <!--v-if-->
-              </div>
-            </li>
-            
-            <li
-              class="t-upload__card-item"
+            <svg
+              class="t-icon t-icon-add t-upload__add-icon"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
             >
-              <div
-                class="t-upload__card-container t-upload__card-box"
-              >
-                <svg
-                  class="t-icon t-icon-add"
-                  fill="none"
-                  height="1em"
-                  viewBox="0 0 16 16"
-                  width="1em"
-                >
-                  <path
-                    d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
-                    fill="currentColor"
-                    fill-opacity="0.9"
-                  />
-                </svg>
-              </div>
-            </li>
-          </ul>
+              <path
+                d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          
           <input
             accept="image/png"
             hidden=""
@@ -241,7 +165,7 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
       <p
         class="tdesign-mobile-demo-block__summary tdesign-mobile-demo-block_subtitle"
       >
-        多选上传图片
+        多选上传
       </p>
     </div>
     <div
@@ -256,154 +180,217 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
           class="upload-title"
           data-v-5eaaef94=""
         >
-          多选上传图片
+          多选上传
         </div>
         <div
+          class="t-upload"
           data-v-5eaaef94=""
+          grid-config="[object Object]"
         >
-          <ul
-            class="t-upload__card"
+          
+          <div
+            class="t-upload__item"
           >
-            
-            <li
-              class="t-upload__card-item"
-              style="flex-basis: 25%;"
+            <div
+              class="t-image t-image--round t-upload__image"
             >
               <div
-                class="t-upload__card-content t-upload__card-box"
+                class="t-image__mask"
               >
                 <div
-                  class="t-upload__card-delete-item"
+                  class="t-loading"
+                  style="font-size: 20px;"
                 >
-                  <svg
-                    class="t-icon t-icon-close close-icon"
-                    fill="none"
-                    height="1em"
-                    viewBox="0 0 16 16"
-                    width="1em"
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
                   >
-                    <path
-                      d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
-                      fill="currentColor"
-                      fill-opacity="0.9"
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
                     />
-                  </svg>
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
                 </div>
+              </div>
+              <picture>
+                <!--v-if-->
                 <img
-                  class="t-upload__card-image"
-                  src="https://tdesign.gtimg.com/site/upload1.png"
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/miniprogram/images/example4.png"
+                  style="object-fit: fill; object-position: center;"
                 />
-                <!--上传失败时，reload重试-->
-                <!--v-if-->
-              </div>
-            </li>
-            <li
-              class="t-upload__card-item"
-              style="flex-basis: 25%;"
+              </picture>
+            </div>
+            <!--v-if-->
+            <svg
+              class="t-icon t-icon-close t-upload__delete-btn"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          <div
+            class="t-upload__item"
+          >
+            <div
+              class="t-image t-image--round t-upload__image"
             >
               <div
-                class="t-upload__card-content t-upload__card-box"
+                class="t-image__mask"
               >
                 <div
-                  class="t-upload__card-delete-item"
+                  class="t-loading"
+                  style="font-size: 20px;"
                 >
-                  <svg
-                    class="t-icon t-icon-close close-icon"
-                    fill="none"
-                    height="1em"
-                    viewBox="0 0 16 16"
-                    width="1em"
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
                   >
-                    <path
-                      d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
-                      fill="currentColor"
-                      fill-opacity="0.9"
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
                     />
-                  </svg>
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
                 </div>
+              </div>
+              <picture>
+                <!--v-if-->
                 <img
-                  class="t-upload__card-image"
-                  src="https://tdesign.gtimg.com/site/upload2.png"
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/miniprogram/images/example6.png"
+                  style="object-fit: fill; object-position: center;"
                 />
-                <!--上传失败时，reload重试-->
-                <!--v-if-->
-              </div>
-            </li>
-            <li
-              class="t-upload__card-item"
-              style="flex-basis: 25%;"
+              </picture>
+            </div>
+            <!--v-if-->
+            <svg
+              class="t-icon t-icon-close t-upload__delete-btn"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          <div
+            class="t-upload__item"
+          >
+            <div
+              class="t-image t-image--round t-upload__image"
             >
               <div
-                class="t-upload__card-content t-upload__card-box"
+                class="t-image__mask"
               >
                 <div
-                  class="t-upload__card-delete-item"
+                  class="t-loading"
+                  style="font-size: 20px;"
                 >
-                  <svg
-                    class="t-icon t-icon-close close-icon"
-                    fill="none"
-                    height="1em"
-                    viewBox="0 0 16 16"
-                    width="1em"
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
                   >
-                    <path
-                      d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
-                      fill="currentColor"
-                      fill-opacity="0.9"
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
                     />
-                  </svg>
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
                 </div>
+              </div>
+              <picture>
+                <!--v-if-->
                 <img
-                  class="t-upload__card-image"
-                  src="https://tdesign.gtimg.com/site/upload1.png"
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/miniprogram/images/example5.png"
+                  style="object-fit: fill; object-position: center;"
                 />
-                <!--上传失败时，reload重试-->
-                <div
-                  class="t-upload__card-mask"
-                >
-                  <span
-                    class="t-upload__card-mask-item"
-                  >
-                    <svg
-                      class="t-icon t-icon-refresh"
-                      fill="none"
-                      height="1em"
-                      viewBox="0 0 16 16"
-                      width="1em"
-                    >
-                      <path
-                        d="M8 2.71c2.9 0 5.25 2.36 5.25 5.29h.96a6.2 6.2 0 00-11.5-3.28V2.64h-.96v3.1c0 .29.22.5.5.5h3.09v-.96H3.49A5.25 5.25 0 018 2.71zM1.79 8h.96a5.25 5.25 0 009.76 2.71h-1.85v-.96h3.09c.28 0 .5.22.5.5v3.1h-.96v-2.07A6.2 6.2 0 011.8 8z"
-                        fill="currentColor"
-                        fill-opacity="0.9"
-                      />
-                    </svg>
-                  </span>
-                </div>
-              </div>
-            </li>
-            
-            <li
-              class="t-upload__card-item"
+              </picture>
+            </div>
+            <!--v-if-->
+            <svg
+              class="t-icon t-icon-close t-upload__delete-btn"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
             >
-              <div
-                class="t-upload__card-container t-upload__card-box"
-              >
-                <svg
-                  class="t-icon t-icon-add"
-                  fill="none"
-                  height="1em"
-                  viewBox="0 0 16 16"
-                  width="1em"
-                >
-                  <path
-                    d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
-                    fill="currentColor"
-                    fill-opacity="0.9"
-                  />
-                </svg>
-              </div>
-            </li>
-          </ul>
+              <path
+                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          
+          
+          <div
+            class="t-upload__item t-upload__item--add"
+          >
+            <svg
+              class="t-icon t-icon-add t-upload__add-icon"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          
           <input
             accept=""
             hidden=""
@@ -430,39 +417,120 @@ exports[`Upload > Upload mobileVue demo works fine 1`] = `
       
     </div>
   </div>
-</div>
-`;
-
-exports[`Upload > Upload multipleVue demo works fine 1`] = `
-<div
-  class="upload-demo"
-  data-v-5eaaef94=""
->
   <div
-    class="upload-title"
-    data-v-5eaaef94=""
-  >
-    多选上传图片
-  </div>
-  <div
-    data-v-5eaaef94=""
+    class="tdesign-mobile-demo-block"
   >
-    <ul
-      class="t-upload__card"
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <h2
+        class="tdesign-mobile-demo-block__title"
+      >
+        02 组件状态
+      </h2>
+      <p
+        class="tdesign-mobile-demo-block__summary"
+      >
+        加载状态
+      </p>
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot"
     >
       
-      <li
-        class="t-upload__card-item"
-        style="flex-basis: 25%;"
+      
+      <div
+        class="upload-demo"
+        data-v-12872376=""
       >
         <div
-          class="t-upload__card-content t-upload__card-box"
+          class="upload-title"
+          data-v-12872376=""
+        >
+          上传图片
+        </div>
+        <div
+          class="t-upload"
+          data-v-12872376=""
         >
+          
           <div
-            class="t-upload__card-delete-item"
+            class="t-upload__item"
           >
+            <div
+              class="t-image t-image--round t-upload__image"
+            >
+              <div
+                class="t-image__mask"
+              >
+                <div
+                  class="t-loading"
+                  style="font-size: 20px;"
+                >
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
+                  >
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
+                </div>
+              </div>
+              <picture>
+                <!--v-if-->
+                <img
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/site/upload1.png"
+                  style="object-fit: fill; object-position: center;"
+                />
+              </picture>
+            </div>
+            <div
+              bind:tap="onFileClick"
+              class="t-upload__progress-mask"
+              data-file="{{file}}"
+              data-index="{{index}}"
+            >
+              
+              <svg
+                aria-hidden=""
+                class="t-icon t-icon-loading t-upload__progress-loading"
+                fill="none"
+                height="1em"
+                viewBox="0 0 16 16"
+                width="1em"
+              >
+                <path
+                  d="M8 1.5a6.5 6.5 0 000 13v-1.63A4.87 4.87 0 1112.88 8h1.62A6.5 6.5 0 008 1.5z"
+                  fill="currentColor"
+                  fill-opacity="0.9"
+                />
+              </svg>
+              <div
+                class="t-upload__progress-text"
+              >
+                上传中...
+              </div>
+              
+              <!--v-if-->
+            </div>
             <svg
-              class="t-icon t-icon-close close-icon"
+              class="t-icon t-icon-close t-upload__delete-btn"
               fill="none"
               height="1em"
               viewBox="0 0 16 16"
@@ -475,26 +543,83 @@ exports[`Upload > Upload multipleVue demo works fine 1`] = `
               />
             </svg>
           </div>
-          <img
-            class="t-upload__card-image"
-            src="https://tdesign.gtimg.com/site/upload1.png"
-          />
-          <!--上传失败时，reload重试-->
-          <!--v-if-->
-        </div>
-      </li>
-      <li
-        class="t-upload__card-item"
-        style="flex-basis: 25%;"
-      >
-        <div
-          class="t-upload__card-content t-upload__card-box"
-        >
           <div
-            class="t-upload__card-delete-item"
+            class="t-upload__item"
           >
+            <div
+              class="t-image t-image--round t-upload__image"
+            >
+              <div
+                class="t-image__mask"
+              >
+                <div
+                  class="t-loading"
+                  style="font-size: 20px;"
+                >
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
+                  >
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
+                </div>
+              </div>
+              <picture>
+                <!--v-if-->
+                <img
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/site/upload1.png"
+                  style="object-fit: fill; object-position: center;"
+                />
+              </picture>
+            </div>
+            <div
+              bind:tap="onFileClick"
+              class="t-upload__progress-mask"
+              data-file="{{file}}"
+              data-index="{{index}}"
+            >
+              
+              <svg
+                aria-hidden=""
+                class="t-icon t-icon-loading t-upload__progress-loading"
+                fill="none"
+                height="1em"
+                viewBox="0 0 16 16"
+                width="1em"
+              >
+                <path
+                  d="M8 1.5a6.5 6.5 0 000 13v-1.63A4.87 4.87 0 1112.88 8h1.62A6.5 6.5 0 008 1.5z"
+                  fill="currentColor"
+                  fill-opacity="0.9"
+                />
+              </svg>
+              <div
+                class="t-upload__progress-text"
+              >
+                68%
+              </div>
+              
+              <!--v-if-->
+            </div>
             <svg
-              class="t-icon t-icon-close close-icon"
+              class="t-icon t-icon-close t-upload__delete-btn"
               fill="none"
               height="1em"
               viewBox="0 0 16 16"
@@ -507,89 +632,429 @@ exports[`Upload > Upload multipleVue demo works fine 1`] = `
               />
             </svg>
           </div>
-          <img
-            class="t-upload__card-image"
-            src="https://tdesign.gtimg.com/site/upload2.png"
-          />
-          <!--上传失败时，reload重试-->
-          <!--v-if-->
-        </div>
-      </li>
-      <li
-        class="t-upload__card-item"
-        style="flex-basis: 25%;"
-      >
-        <div
-          class="t-upload__card-content t-upload__card-box"
-        >
+          
+          
           <div
-            class="t-upload__card-delete-item"
+            class="t-upload__item t-upload__item--add"
           >
             <svg
-              class="t-icon t-icon-close close-icon"
+              class="t-icon t-icon-add t-upload__add-icon"
               fill="none"
               height="1em"
               viewBox="0 0 16 16"
               width="1em"
             >
               <path
-                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+                d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
                 fill="currentColor"
                 fill-opacity="0.9"
               />
             </svg>
           </div>
-          <img
-            class="t-upload__card-image"
-            src="https://tdesign.gtimg.com/site/upload1.png"
+          
+          <input
+            accept="image/png"
+            hidden=""
+            type="file"
           />
-          <!--上传失败时，reload重试-->
+          <transition-stub
+            appear="false"
+            class="t-image-viewer"
+            css="true"
+            name="t-overlay"
+            persisted="true"
+          >
+            <div
+              class="t-overlay"
+              style="z-index: 1000; transition-duration: 300ms; display: none;"
+            >
+              
+              
+            </div>
+          </transition-stub>
+        </div>
+      </div>
+      <div
+        class="upload-demo__title"
+        data-v-12872376=""
+      >
+        上传失败
+      </div>
+      <div
+        class="upload-demo"
+        data-v-12872376=""
+      >
+        <div
+          class="upload-title"
+          data-v-12872376=""
+        >
+          上传图片
+        </div>
+        <div
+          class="t-upload"
+          data-v-12872376=""
+        >
+          
           <div
-            class="t-upload__card-mask"
+            class="t-upload__item"
           >
-            <span
-              class="t-upload__card-mask-item"
+            <div
+              class="t-image t-image--round t-upload__image"
+            >
+              <div
+                class="t-image__mask"
+              >
+                <div
+                  class="t-loading"
+                  style="font-size: 20px;"
+                >
+                  
+                  <div
+                    class="t-loading__dots"
+                    style="animation-duration: 800ms; width: 20px; height: 20px;"
+                  >
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+                    />
+                    <div
+                      class="t-loading__dot"
+                      style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+                    />
+                  </div>
+                  
+                  <!--v-if-->
+                  <!---->
+                </div>
+              </div>
+              <picture>
+                <!--v-if-->
+                <img
+                  alt=""
+                  class="t-image__img"
+                  src="https://tdesign.gtimg.com/site/upload1.png"
+                  style="object-fit: fill; object-position: center;"
+                />
+              </picture>
+            </div>
+            <div
+              bind:tap="onFileClick"
+              class="t-upload__progress-mask"
+              data-file="{{file}}"
+              data-index="{{index}}"
             >
               <svg
-                class="t-icon t-icon-refresh"
+                aria-hidden=""
+                class="t-icon t-icon-close-circle"
                 fill="none"
                 height="1em"
                 viewBox="0 0 16 16"
                 width="1em"
               >
                 <path
-                  d="M8 2.71c2.9 0 5.25 2.36 5.25 5.29h.96a6.2 6.2 0 00-11.5-3.28V2.64h-.96v3.1c0 .29.22.5.5.5h3.09v-.96H3.49A5.25 5.25 0 018 2.71zM1.79 8h.96a5.25 5.25 0 009.76 2.71h-1.85v-.96h3.09c.28 0 .5.22.5.5v3.1h-.96v-2.07A6.2 6.2 0 011.8 8z"
+                  d="M4.98 10.31L7.3 8 5 5.69l.7-.7L8 7.28 10.31 5l.7.7L8.72 8l2.3 2.31-.7.7L8 8.72 5.69 11l-.7-.7z"
+                  fill="currentColor"
+                  fill-opacity="0.9"
+                />
+                <path
+                  d="M8 1a7 7 0 110 14A7 7 0 018 1zm0 1a6 6 0 100 12A6 6 0 008 2z"
                   fill="currentColor"
                   fill-opacity="0.9"
                 />
               </svg>
-            </span>
+              <div
+                class="t-upload__progress-text"
+              >
+                上传失败
+              </div>
+            </div>
+            <svg
+              class="t-icon t-icon-close t-upload__delete-btn"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
           </div>
+          
+          
+          <div
+            class="t-upload__item t-upload__item--add"
+          >
+            <svg
+              class="t-icon t-icon-add t-upload__add-icon"
+              fill="none"
+              height="1em"
+              viewBox="0 0 16 16"
+              width="1em"
+            >
+              <path
+                d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
+                fill="currentColor"
+                fill-opacity="0.9"
+              />
+            </svg>
+          </div>
+          
+          <input
+            accept="image/png"
+            hidden=""
+            type="file"
+          />
+          <transition-stub
+            appear="false"
+            class="t-image-viewer"
+            css="true"
+            name="t-overlay"
+            persisted="true"
+          >
+            <div
+              class="t-overlay"
+              style="z-index: 1000; transition-duration: 300ms; display: none;"
+            >
+              
+              
+            </div>
+          </transition-stub>
         </div>
-      </li>
+      </div>
       
-      <li
-        class="t-upload__card-item"
+      
+    </div>
+  </div>
+</div>
+`;
+
+exports[`Upload > Upload multipleVue demo works fine 1`] = `
+<div
+  class="upload-demo"
+  data-v-5eaaef94=""
+>
+  <div
+    class="upload-title"
+    data-v-5eaaef94=""
+  >
+    多选上传
+  </div>
+  <div
+    class="t-upload"
+    data-v-5eaaef94=""
+    grid-config="[object Object]"
+  >
+    
+    <div
+      class="t-upload__item"
+    >
+      <div
+        class="t-image t-image--round t-upload__image"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example4.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <!--v-if-->
+      <svg
+        class="t-icon t-icon-close t-upload__delete-btn"
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    <div
+      class="t-upload__item"
+    >
+      <div
+        class="t-image t-image--round t-upload__image"
       >
         <div
-          class="t-upload__card-container t-upload__card-box"
+          class="t-image__mask"
         >
-          <svg
-            class="t-icon t-icon-add"
-            fill="none"
-            height="1em"
-            viewBox="0 0 16 16"
-            width="1em"
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
           >
-            <path
-              d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
-              fill="currentColor"
-              fill-opacity="0.9"
-            />
-          </svg>
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
         </div>
-      </li>
-    </ul>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example6.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <!--v-if-->
+      <svg
+        class="t-icon t-icon-close t-upload__delete-btn"
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    <div
+      class="t-upload__item"
+    >
+      <div
+        class="t-image t-image--round t-upload__image"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/miniprogram/images/example5.png"
+            style="object-fit: fill; object-position: center;"
+          />
+        </picture>
+      </div>
+      <!--v-if-->
+      <svg
+        class="t-icon t-icon-close t-upload__delete-btn"
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M8 8.92L11.08 12l.92-.92L8.92 8 12 4.92 11.08 4 8 7.08 4.92 4 4 4.92 7.08 8 4 11.08l.92.92L8 8.92z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
+    
+    <div
+      class="t-upload__item t-upload__item--add"
+    >
+      <svg
+        class="t-icon t-icon-add t-upload__add-icon"
+        fill="none"
+        height="1em"
+        viewBox="0 0 16 16"
+        width="1em"
+      >
+        <path
+          d="M7.35 8.65v3.85h1.3V8.65h3.85v-1.3H8.65V3.5h-1.3v3.85H3.5v1.3h3.85z"
+          fill="currentColor"
+          fill-opacity="0.9"
+        />
+      </svg>
+    </div>
+    
     <input
       accept=""
       hidden=""
diff --git a/src/upload/__test__/index.test.jsx b/src/upload/__test__/index.test.jsx
index 7a8a1ce1..36abeeb0 100644
--- a/src/upload/__test__/index.test.jsx
+++ b/src/upload/__test__/index.test.jsx
@@ -58,7 +58,7 @@ const triggerUploadFile = (node, fileList) => {
 
 describe('Upload', () => {
   describe('props', () => {
-    it(': action', async () => {
+    it(':action', async () => {
       const onProgress = vi.fn();
 
       const wrapper = mount(Upload, {
@@ -74,7 +74,7 @@ describe('Upload', () => {
       expect(onProgress).toHaveBeenCalled();
     });
 
-    it(': allowUploadDuplicateFile', async () => {
+    it(':allowUploadDuplicateFile', async () => {
       const props = {
         autoUpload: false,
         allowUploadDuplicateFile: true,
@@ -100,7 +100,7 @@ describe('Upload', () => {
       expect(wrapper.vm.toUploadFiles.length).toBe(2);
     });
 
-    it(': disabled', async () => {
+    it(':disabled', async () => {
       const onSelectChange = vi.fn();
 
       const props = {
@@ -117,7 +117,7 @@ describe('Upload', () => {
       expect(onSelectChange).not.toHaveBeenCalled();
     });
 
-    it(': files', async () => {
+    it(':files', async () => {
       const files = ref([]);
 
       const wrapper = mount(<Upload requestMethod={requestMethod} v-model={files.value} />);
@@ -126,7 +126,7 @@ describe('Upload', () => {
       expect(files.value.length).toBe(1);
     });
 
-    it(': defaultFiles', async () => {
+    it(':defaultFiles', async () => {
       const defaultFiles = ref([]);
 
       const wrapper = mount({
@@ -139,31 +139,7 @@ describe('Upload', () => {
       expect(defaultFiles.value.length).toBe(0);
     });
 
-    it(': gridConfig', async () => {
-      const gridConfig = ref({
-        column: 2,
-      });
-
-      const props = {
-        requestMethod,
-        gridConfig: gridConfig.value,
-        multiple: true,
-        allowUploadDuplicateFile: true,
-      };
-
-      const wrapper = mount(Upload, {
-        props,
-      });
-
-      await wrapper.findComponent(Upload).setValue([mockFileFoo, mockFileBar, mockFileFoo, mockFileBar]);
-
-      expect(wrapper.vm.itemStyle).toStrictEqual({ flexBasis: `${100 / 2}%` });
-
-      gridConfig.value.column = 4;
-      expect(wrapper.vm.itemStyle).toStrictEqual({ flexBasis: `${100 / 4}%` });
-    });
-
-    it(': max', async () => {
+    it(':max', async () => {
       const props = {
         requestMethod,
         allowUploadDuplicateFile: true,
@@ -179,7 +155,7 @@ describe('Upload', () => {
       expect(wrapper.vm.toUploadFiles.length).toBe(3);
     });
 
-    it(': multiple', async () => {
+    it(':multiple', async () => {
       const props = {
         autoUpload: false,
         multiple: true,
@@ -194,7 +170,7 @@ describe('Upload', () => {
       expect(wrapper.vm.toUploadFiles.length).toBe(2);
     });
 
-    it(': requestMethod', async () => {
+    it(':requestMethod', async () => {
       const onSuccess = vi.fn();
       const onFail = vi.fn();
       const response = ref({
@@ -256,7 +232,7 @@ describe('Upload', () => {
       expect(onFail).toHaveBeenCalledTimes(2);
     });
 
-    it(': sizeLimit', () => {
+    it(':sizeLimit', () => {
       const props = {
         requestMethod,
         sizeLimit: {
@@ -289,7 +265,7 @@ describe('Upload', () => {
   });
 
   describe('slots', () => {
-    it(': deleteBtn', async () => {
+    it(':deleteBtn', async () => {
       const props = {
         requestMethod,
         deleteBtn: () => <AddIcon />,
@@ -323,7 +299,7 @@ describe('Upload', () => {
   });
 
   describe('event', () => {
-    it(': events', async () => {
+    it(':events', async () => {
       const props = {
         requestMethod,
       };
@@ -338,7 +314,7 @@ describe('Upload', () => {
       expect(wrapper.emitted()).toHaveProperty('select-change');
       expect(wrapper.emitted()).toHaveProperty('success');
 
-      await wrapper.find('.t-upload__card-image').trigger('click');
+      await wrapper.find('.t-upload__image').trigger('click');
       expect(wrapper.emitted()).toHaveProperty('preview');
 
       await wrapper.findComponent(CloseIcon).trigger('click');
@@ -347,7 +323,7 @@ describe('Upload', () => {
   });
 
   describe('function', () => {
-    it(': beforeUpload', async () => {
+    it(':beforeUpload', async () => {
       const canUpload = ref(false);
       const beforeUpload = vi.fn(() => canUpload.value);
 
@@ -371,7 +347,7 @@ describe('Upload', () => {
       expect(beforeUpload).toHaveReturnedWith(true);
     });
 
-    it(': format', async () => {
+    it(':format', async () => {
       const format = vi.fn((file) => ({ ...file, name: 'bar.png', raw: file }));
 
       const props = {
@@ -389,7 +365,7 @@ describe('Upload', () => {
       expect(wrapper.vm.toUploadFiles[0].name).toBe('bar.png');
     });
 
-    it(': onFail', async () => {
+    it(':onFail', async () => {
       const onFail = vi.fn();
 
       const props = {
@@ -411,41 +387,6 @@ describe('Upload', () => {
 
       await sleep(0);
       expect(onFail).toHaveBeenCalled();
-
-      const spy = vi.spyOn(wrapper.vm, 'handleReload');
-      await wrapper.findComponent(RefreshIcon).trigger('click');
-      expect(spy).toHaveBeenCalled();
-    });
-
-    it(': on-functions', async () => {
-      const onSelectChange = vi.fn();
-      const onSuccess = vi.fn();
-      const onPreview = vi.fn();
-      const onRemove = vi.fn();
-
-      const props = {
-        requestMethod,
-        onSelectChange,
-        onSuccess,
-        onPreview,
-        onRemove,
-      };
-
-      const wrapper = mount(Upload, {
-        props,
-      });
-
-      triggerUploadFile(wrapper, [mockFileFoo]);
-
-      await sleep(0);
-      expect(onSelectChange).toHaveBeenCalled();
-      expect(onSuccess).toHaveBeenCalled();
-
-      await wrapper.find('.t-upload__card-image').trigger('click');
-      expect(onPreview).toHaveBeenCalled();
-
-      await wrapper.findComponent(CloseIcon).trigger('click');
-      expect(onRemove).toHaveBeenCalled();
     });
   });
 });