Repository: Tencent/tdesign-mobile-vue
Pull request #1334 (2024-04-23 09:55:06)

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


github-actions[bot]: <a href="https://preview-pr1334-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/8798486835) -->
<!-- AUTO_PREVIEW_HOOK -->

Patch:
diff --git a/src/avatar/avatar-group.tsx b/src/avatar/avatar-group.tsx
new file mode 100644
index 00000000..366e4641
--- /dev/null
+++ b/src/avatar/avatar-group.tsx
@@ -0,0 +1,73 @@
+import { computed, defineComponent, Fragment, provide, RendererNode } from 'vue';
+
+import AvatarGroupProps from './avatar-group-props';
+import config from '../config';
+import TAvatar from './avatar';
+
+import { useTNodeJSX } from '../hooks/tnode';
+import { usePrefixClass } from '../hooks/useClass';
+
+const { prefix } = config;
+const name = `${prefix}-avatar-group`;
+
+export default defineComponent({
+  name,
+  props: AvatarGroupProps,
+  setup(props) {
+    const renderTNodeJSX = useTNodeJSX();
+    const avatarGroupClass = usePrefixClass('avatar-group');
+
+    provide('avatarGroup', { ...props });
+
+    const direction = props.cascading ? props.cascading.split('-')[0] : 'right';
+
+    const avatarGroupClasses = computed(() => [
+      `${avatarGroupClass.value}`,
+      `${avatarGroupClass.value}-offset-${direction}-${props.size.indexOf('px') > -1 ? 'medium' : props.size}`,
+    ]);
+
+    const readerAvatar = () => {
+      const children: Array<RendererNode> = renderTNodeJSX('default');
+      const allChildren: Array<RendererNode> = [];
+
+      children.forEach((child) => {
+        if (child.type === Fragment) {
+          allChildren.push(...child.children);
+        } else {
+          allChildren.push(child);
+        }
+      });
+
+      let isShowCollapse = false;
+      let avatarList: Array<RendererNode> = [];
+      if (allChildren.length > props.max) {
+        avatarList = allChildren.slice(0, props.max);
+        isShowCollapse = true;
+      } else {
+        avatarList = allChildren;
+      }
+
+      if (props.cascading === 'left-up') {
+        const defaultZIndex = 100;
+        for (let index = 0; index < avatarList.length; index++) {
+          avatarList[index].props.style = `z-index: ${defaultZIndex - index * 10}`;
+        }
+      }
+
+      if (isShowCollapse) {
+        const collapseAvatar = renderTNodeJSX('collapseAvatar');
+        avatarList.push(
+          <TAvatar size={avatarList[0].size || props.size}>
+            {collapseAvatar || `+${allChildren.length - props.max}`}
+          </TAvatar>,
+        );
+      }
+
+      return avatarList;
+    };
+
+    return () => {
+      return <div class={avatarGroupClasses.value}>{readerAvatar()}</div>;
+    };
+  },
+});
diff --git a/src/avatar/avatar-group.vue b/src/avatar/avatar-group.vue
deleted file mode 100644
index 1c1608d8..00000000
--- a/src/avatar/avatar-group.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<template>
-  <div :class="classes">
-    <component :is="avatarItems" />
-    <avatar v-if="isShowEllipsisContent" :size="size">
-      <t-node :content="ellipsisContent"></t-node>
-    </avatar>
-  </div>
-</template>
-
-<script lang="ts">
-import { computed, defineComponent, Fragment, getCurrentInstance, provide, ref } from 'vue';
-import { renderTNode, TNode } from '../shared';
-import AvatarGroupProps from './avatar-group-props';
-import { TdAvatarProps } from './type';
-import config from '../config';
-import Avatar from './avatar.vue';
-
-const { prefix } = config;
-const name = `${prefix}-avatar-group`;
-
-export default defineComponent({
-  name,
-  components: {
-    Avatar,
-    TNode,
-  },
-  props: AvatarGroupProps,
-  setup(props, { slots }) {
-    provide('avatarGroup', { ...props });
-
-    const internalInstance = getCurrentInstance();
-    const direction = props.cascading ? props.cascading.split('-')[0] : 'right';
-    const classes = computed(() => [
-      `${name}`,
-      `${name}-offset-${direction}-${props.size.indexOf('px') > -1 ? 'medium' : props.size}`,
-    ]);
-
-    const isShowEllipsisContent = ref(false);
-    const ellipsisContent = ref(null);
-    const size = ref(props.size);
-
-    const collapseAvatar = computed(() => renderTNode(internalInstance, 'collapseAvatar'));
-
-    const avatarItems = () => {
-      const childContent: any[] = slots.default ? slots.default() : [];
-      const children: TdAvatarProps[] = [];
-      childContent.forEach((child) => {
-        if (child.type === Fragment) {
-          children.push(...child.children);
-        } else {
-          children.push(child);
-        }
-      });
-      let childrenShow: any[] = [];
-      const max = props.max || 0;
-      if (max && max < children.length) {
-        childrenShow = children.slice(0, max);
-        isShowEllipsisContent.value = true;
-        ellipsisContent.value = collapseAvatar.value || `+${children.length - max}`;
-      } else {
-        childrenShow = children;
-      }
-      size.value = childrenShow[0].size || props.size;
-      if (props.cascading === 'left-up') {
-        childrenShow.forEach((item, index) => {
-          const defaultZIndex = 100;
-          childrenShow[index].props.style = `z-index: ${defaultZIndex - index * 10}`;
-        });
-      }
-      return childrenShow;
-    };
-    return {
-      classes,
-      size,
-      isShowEllipsisContent,
-      ellipsisContent,
-      avatarItems,
-    };
-  },
-});
-</script>
diff --git a/src/avatar/avatar.en-US.md b/src/avatar/avatar.en-US.md
index 1235d74b..12b81550 100644
--- a/src/avatar/avatar.en-US.md
+++ b/src/avatar/avatar.en-US.md
@@ -1,6 +1,7 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Avatar Props
 
 name | type | default | description | required
@@ -11,7 +12,7 @@ hideOnLoadFailed | Boolean | false | hide image when loading image failed | N
 icon | Slot / Function | - | use icon to fill。Typescript：`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 image | String | - | images url | 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/avatar/type.ts) | N
-shape | String | circle | shape。options：circle/round。Typescript：`ShapeEnum ` `type ShapeEnum = 'circle' \| 'round'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
+shape | String | circle | shape。options: circle/round。Typescript：`ShapeEnum ` `type ShapeEnum = 'circle' \| 'round'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
 size | String | medium | size | N
 onError | Function |  | Typescript：`(context: { e: ImageEvent }) => void`<br/>trigger on image load failed | N
 
@@ -21,17 +22,18 @@ name | params | description
 -- | -- | --
 error | `(context: { e: ImageEvent })` | trigger on image load failed
 
+
 ### AvatarGroup Props
 
 name | type | default | description | required
 -- | -- | -- | -- | --
-cascading | String | 'right-up' | multiple images cascading。options：left-up/right-up。Typescript：`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
+cascading | String | 'right-up' | multiple images cascading。options: left-up/right-up。Typescript：`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
 collapseAvatar | String / Slot / Function | - | Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 max | Number | - | \- | N
 size | String | medium | size | N
 
+### CSS 变量
 
-### CSS Variables
 The component provides the following CSS variables, which can be used to customize styles.
 Name | Default Value | Description 
 -- | -- | --
@@ -55,4 +57,4 @@ Name | Default Value | Description
 --td-avatar-small-width | 40px | - 
 --td-avatar-text-large-font-size | 16px | - 
 --td-avatar-text-medium-font-size | @font-size-base | - 
---td-avatar-text-small-font-size | @font-size-s | - 
+--td-avatar-text-small-font-size | @font-size-s | -
\ No newline at end of file
diff --git a/src/avatar/avatar.md b/src/avatar/avatar.md
index d4183055..69b7371c 100644
--- a/src/avatar/avatar.md
+++ b/src/avatar/avatar.md
@@ -1,9 +1,10 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Avatar Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
 alt | String | - | 头像替换文本，仅当图片加载失败时有效 | N
 badgeProps | Object | - | 头像右上角提示信息，继承 Badge 组件的全部特性。如：小红点，或者数字。TS 类型：`BadgeProps`，[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
@@ -21,17 +22,18 @@ onError | Function |  | TS 类型：`(context: { e: ImageEvent }) => void`<br/>
 -- | -- | --
 error | `(context: { e: ImageEvent })` | 图片加载失败时触发
 
+
 ### AvatarGroup Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
 cascading | String | 'right-up' | 图片之间的层叠关系，可选值：左侧图片在上和右侧图片在上。可选项：left-up/right-up。TS 类型：`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/avatar/type.ts) | N
 collapseAvatar | String / Slot / Function | - | 头像数量超出时，会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例：`+5`，`...`, `更多`。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 max | Number | - | 能够同时显示的最多头像数量 | N
 size | String | medium | 尺寸，示例值：small/medium/large/24px/38px 等。优先级低于 Avatar.size | N
 
-
 ### CSS 变量
+
 组件提供了下列 CSS 变量，可用于自定义样式。
 名称 | 默认值 | 描述 
 -- | -- | --
@@ -55,4 +57,4 @@ size | String | medium | 尺寸，示例值：small/medium/large/24px/38px 等
 --td-avatar-small-width | 40px | - 
 --td-avatar-text-large-font-size | 16px | - 
 --td-avatar-text-medium-font-size | @font-size-base | - 
---td-avatar-text-small-font-size | @font-size-s | - 
+--td-avatar-text-small-font-size | @font-size-s | -
\ No newline at end of file
diff --git a/src/avatar/avatar.tsx b/src/avatar/avatar.tsx
new file mode 100644
index 00000000..03eb3579
--- /dev/null
+++ b/src/avatar/avatar.tsx
@@ -0,0 +1,82 @@
+import { computed, defineComponent, getCurrentInstance, inject, ref } from 'vue';
+import TBadge from '../badge';
+import TImage from '../image';
+import config from '../config';
+import AvatarProps from './props';
+import { TdAvatarGroupProps, TdAvatarProps } from './type';
+import CLASSNAMES from '../shared/constants';
+import { useContent, useTNodeJSX } from '../hooks/tnode';
+import { usePrefixClass } from '../hooks/useClass';
+
+const { prefix } = config;
+const name = `${prefix}-avatar`;
+
+export default defineComponent({
+  name,
+  props: AvatarProps,
+  setup(props) {
+    const renderTNodeJSX = useTNodeJSX();
+    const renderTNodeContent = useContent();
+    const avatarClass = usePrefixClass('avatar');
+
+    const avatarGroupProps = inject<TdAvatarGroupProps>('avatarGroup', {});
+    const hasAvatarGroupProps = Object.keys(avatarGroupProps).length > 0;
+
+    const sizeValue = ref(props.size || (avatarGroupProps && avatarGroupProps.size));
+    const sizeReValue = ref((avatarGroupProps && avatarGroupProps.size) || props.size);
+    const sizeClass = `${sizeReValue.value.indexOf('px') > -1 ? 'medium' : sizeReValue.value}`;
+    const avatarClasses = computed(() => [
+      `${avatarClass.value}`,
+      `${avatarClass.value}--${sizeClass}`,
+      {
+        [`${avatarClass.value}--${props.shape}`]: props.shape,
+      },
+      hasAvatarGroupProps ? `${avatarClass.value}--border ${avatarClass.value}--border-${sizeClass}` : '',
+    ]);
+
+    const isCustomSize = computed(() => sizeValue.value && !CLASSNAMES.SIZE[sizeValue.value]);
+    const customSize = computed(() => {
+      return isCustomSize.value
+        ? {
+            height: sizeValue.value,
+            width: sizeValue.value,
+          }
+        : {};
+    });
+
+    const handleImgLoadError = (e: any) => {
+      props.onError?.(e);
+    };
+    return () => {
+      const icon = renderTNodeJSX('icon');
+      const TNodeContent = renderTNodeContent('default', 'content');
+
+      const readerAvatar = () => {
+        if (props.image && !props.hideOnLoadFailed) {
+          return (
+            <TImage
+              style={customSize.value}
+              src={props.image}
+              alt={props.alt}
+              {...(props.imageProps as TdAvatarProps['imageProps'])}
+              onError={handleImgLoadError}
+            />
+          );
+        }
+        if (icon) {
+          return <div class={`${avatarClass.value}__icon`}>{icon}</div>;
+        }
+        return <span>{TNodeContent}</span>;
+      };
+      return (
+        <div class={`${avatarClass.value}__wrapper`} style={customSize.value}>
+          <div class={`${avatarClass.value}__badge`}>
+            <TBadge {...(props.badgeProps as TdAvatarProps['badgeProps'])}>
+              <div class={avatarClasses.value}>{readerAvatar()}</div>
+            </TBadge>
+          </div>
+        </div>
+      );
+    };
+  },
+});
diff --git a/src/avatar/avatar.vue b/src/avatar/avatar.vue
deleted file mode 100644
index e1824b44..00000000
--- a/src/avatar/avatar.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-<template>
-  <div :class="`${name}__wrapper`" :style="customSize">
-    <div :class="`${name}__badge`">
-      <t-badge v-bind="badgeProps">
-        <div :class="avatarClass">
-          <t-image
-            v-if="image && !hideOnLoadFailed"
-            :style="customSize"
-            :src="image"
-            :alt="alt"
-            v-bind="imageProps"
-            @error="handleImgLoadError"
-          />
-          <div v-else-if="iconContent !== undefined" :class="`${name}__icon`">
-            <t-node :content="iconContent"></t-node>
-          </div>
-          <span v-else>
-            <t-node :content="avatarContent"></t-node>
-          </span>
-        </div>
-      </t-badge>
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { computed, toRefs, defineComponent, getCurrentInstance, inject, ref } from 'vue';
-import TBadge from '../badge';
-import TImage from '../image';
-import config from '../config';
-import AvatarProps from './props';
-import { TdAvatarGroupProps } from './type';
-import CLASSNAMES from '../shared/constants';
-import { renderContent, renderTNode, TNode } from '../shared';
-
-const { prefix } = config;
-const name = `${prefix}-avatar`;
-
-export default defineComponent({
-  name,
-  components: { TNode, TBadge, TImage },
-  props: AvatarProps,
-  emits: ['error'],
-  setup(props) {
-    const internalInstance = getCurrentInstance();
-    const avatarGroupProps = inject('avatarGroup', {}) as TdAvatarGroupProps;
-    const hasAvatarGroupProps = Object.keys(avatarGroupProps).length > 0;
-    const iconContent = computed(() => renderTNode(internalInstance, 'icon'));
-    const avatarContent = computed(() => renderContent(internalInstance, 'default', 'content'));
-    const sizeValue = ref(props.size || (avatarGroupProps && avatarGroupProps.size));
-    const sizeReValue = ref((avatarGroupProps && avatarGroupProps.size) || props.size);
-    const sizeClass = `${sizeReValue.value.indexOf('px') > -1 ? 'medium' : sizeReValue.value}`;
-    const avatarClass = computed(() => [
-      `${name}`,
-      `${name}--${sizeClass}`,
-      {
-        [`${name}--${props.shape}`]: props.shape,
-      },
-      hasAvatarGroupProps ? `${name}--border ${name}--border-${sizeClass}` : '',
-    ]);
-
-    const isCustomSize = computed(() => sizeValue.value && !CLASSNAMES.SIZE[sizeValue.value]);
-    const customSize = computed(() => {
-      return isCustomSize.value
-        ? {
-            height: sizeValue.value,
-            width: sizeValue.value,
-          }
-        : {};
-    });
-
-    const handleImgLoadError = (e: any) => {
-      props.onError?.(e);
-    };
-
-    return {
-      name,
-      ...toRefs(props),
-      iconContent,
-      avatarContent,
-      avatarClass,
-      customSize,
-      handleImgLoadError,
-    };
-  },
-});
-</script>
diff --git a/src/avatar/index.ts b/src/avatar/index.ts
index 0f72d86a..d0d020b6 100644
--- a/src/avatar/index.ts
+++ b/src/avatar/index.ts
@@ -1,5 +1,5 @@
-import _Avatar from './avatar.vue';
-import _AvatarGroup from './avatar-group.vue';
+import _Avatar from './avatar';
+import _AvatarGroup from './avatar-group';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/dropdown-menu/dropdown-item.vue b/src/dropdown-menu/dropdown-item.tsx
similarity index 65%
rename from src/dropdown-menu/dropdown-item.vue
rename to src/dropdown-menu/dropdown-item.tsx
index be81f635..1f51e205 100644
--- a/src/dropdown-menu/dropdown-item.vue
+++ b/src/dropdown-menu/dropdown-item.tsx
@@ -1,78 +1,3 @@
-<template>
-  <div v-if="wrapperVisible" :id="popupId" :class="classes" :style="{ ...expandStyle }">
-    <t-popup
-      :visible="isShowItems"
-      :duration="duration"
-      :show-overlay="showOverlay"
-      :style="popupStyle"
-      :overlay-props="{ style: 'position: absolute' }"
-      :class="`${name}__popup-host`"
-      :attach="`#${popupId}`"
-      @visible-change="onVisibleChange"
-    >
-      <div ref="popupContent" :class="styleContent" :style="contentStyle">
-        <div :class="`${name}__body`">
-          <slot>
-            <template v-if="!multiple">
-              <!-- 单选列表 -->
-              <t-radio-group v-model="radioSelect" placement="right" :class="`${name}__radio-group`">
-                <template v-for="option in options" :key="option.value">
-                  <t-radio
-                    :value="option.value"
-                    :label="option.label"
-                    :disabled="option.disabled"
-                    :class="styleDropRadio(option.value)"
-                    :checked="isCheckedRadio(option.value)"
-                    icon="line"
-                  />
-                </template>
-              </t-radio-group>
-            </template>
-            <template v-else>
-              <!-- 多选列表 -->
-              <t-checkbox-group
-                v-model="checkSelect"
-                :class="`${name}__checkbox-group`"
-                :style="`grid-template-columns: repeat(${$props.optionsColumns}, 1fr)`"
-              >
-                <template v-for="option in options" :key="option.value">
-                  <t-checkbox
-                    :class="`${name}__checkbox-item t-checkbox--tag`"
-                    :icon="false"
-                    borderless
-                    :value="option.value"
-                    :label="option.label"
-                    :disabled="option.disabled"
-                  />
-                </template>
-              </t-checkbox-group>
-            </template>
-          </slot>
-        </div>
-        <slot name="footer">
-          <div v-if="multiple" :class="`${name}__footer`">
-            <t-button
-              theme="light"
-              :class="`${name}__footer-btn ${name}__reset-btn`"
-              :disabled="isBtnDisabled"
-              @click="resetSelect"
-              >{{ globalConfig.reset }}</t-button
-            >
-            <t-button
-              theme="primary"
-              :class="`${name}__footer-btn ${name}__confirm-btn`"
-              :disabled="isBtnDisabled"
-              @click="confirmSelect"
-              >{{ globalConfig.confirm }}</t-button
-            >
-          </div>
-        </slot>
-      </div>
-    </t-popup>
-  </div>
-</template>
-
-<script lang="ts">
 import { ref, watch, toRefs, inject, computed, reactive, onBeforeMount, defineComponent, nextTick } from 'vue';
 import TRadio, { RadioGroup as TRadioGroup } from '../radio';
 import config from '../config';
@@ -85,6 +10,7 @@ import { DropdownMenuState, DropdownMenuControl } from './context';
 import { TdDropdownMenuProps, DropdownValue } from './type';
 import { KeysType } from '../common';
 import { useConfig } from '../config-provider/useConfig';
+import { useContent, useTNodeJSX } from '../hooks/tnode';
 
 const { prefix } = config;
 const name = `${prefix}-dropdown-item`;
@@ -97,6 +23,9 @@ export default defineComponent({
   emits: ['change', 'open', 'opened', 'close', 'closed', 'update:value', 'update:modelValue'],
   setup(props) {
     const { globalConfig } = useConfig('dropdownMenu');
+    const renderContent = useContent();
+    const renderTNodeJSX = useTNodeJSX();
+    const popupContent = ref(null);
 
     // 受控 value 属性
     const { value, modelValue } = toRefs(props);
@@ -186,8 +115,6 @@ export default defineComponent({
       setTimeout(() => {
         props[`on${val ? 'Opened' : 'Closed'}`]?.();
       }, Number(duration));
-
-      const popupContent = ref(null);
     };
 
     // 根据父组件状态，判断当前是否展开
@@ -272,28 +199,111 @@ export default defineComponent({
         emitEvents('menuClosed', 'overlay');
       }
     };
+    const { showOverlay, duration, isShowItems, wrapperVisible, expandStyle, multiple, options } = toRefs(state);
+
+    return () => {
+      const handleRadioChange = (value: any) => {
+        radioSelect.value = value;
+      };
+      const handleCheckboxChange = (value: any) => {
+        checkSelect.value = value;
+      };
+      const defaultSlot = () => {
+        if (!multiple.value) {
+          // 单选列表
+          return (
+            <t-radio-group
+              value={radioSelect.value}
+              onChange={handleRadioChange}
+              placement="right"
+              class={`${name}__radio-group`}
+            >
+              {(options.value || []).map((option) => (
+                <t-radio
+                  key={option.value}
+                  value={option.value}
+                  label={option.label}
+                  disabled={option.disabled}
+                  class={styleDropRadio(option.value)}
+                  checked={isCheckedRadio(option.value)}
+                  icon="line"
+                />
+              ))}
+            </t-radio-group>
+          );
+        }
+        // 多选列表
+        return (
+          <t-checkbox-group
+            value={checkSelect.value}
+            onChange={handleCheckboxChange}
+            class={`${name}__checkbox-group`}
+            style={`grid-template-columns: repeat(${props.optionsColumns}, 1fr)`}
+          >
+            {(options.value || []).map((option) => (
+              <t-checkbox
+                key={option.value}
+                class={`${name}__checkbox-item t-checkbox--tag`}
+                icon={false}
+                borderless
+                value={option.value}
+                label={option.label}
+                disabled={option.disabled}
+              />
+            ))}
+          </t-checkbox-group>
+        );
+      };
+
+      const footerSlot = () => {
+        if (multiple.value) {
+          return (
+            <div class={`${name}__footer`}>
+              <t-button
+                theme="light"
+                class={`${name}__footer-btn ${name}__reset-btn`}
+                disabled={isBtnDisabled.value}
+                onClick={resetSelect}
+              >
+                {globalConfig.value.reset}
+              </t-button>
+              <t-button
+                theme="primary"
+                class={`${name}__footer-btn ${name}__confirm-btn`}
+                disabled={isBtnDisabled.value}
+                onClick={confirmSelect}
+              >
+                {globalConfig.value.confirm}
+              </t-button>
+            </div>
+          );
+        }
+      };
+
+      const content = renderContent('default', 'content');
 
-    return {
-      name: ref(name),
-      ...toRefs(props),
-      ...toRefs(state),
-      globalConfig,
-      classes,
-      popupStyle,
-      styleContent,
-      contentStyle,
-      isBtnDisabled,
-      radioSelect,
-      checkSelect,
-      popupId,
-      isCheckedRadio,
-      styleDropRadio,
-      expandMenu,
-      collapseMenu,
-      resetSelect,
-      confirmSelect,
-      onVisibleChange,
+      const footer = renderTNodeJSX('footer');
+      return (
+        wrapperVisible.value && (
+          <div id={popupId} class={classes.value} style={{ ...expandStyle.value }}>
+            <t-popup
+              visible={isShowItems.value}
+              duration={duration.value}
+              showOverlay={showOverlay.value}
+              style={popupStyle.value}
+              overlayProps={{ style: 'position: absolute' }}
+              class={`${name}__popup-host`}
+              attach={`#${popupId}`}
+              onVisibleChange={onVisibleChange}
+            >
+              <div ref={popupContent} class={styleContent.value} style={contentStyle.value}>
+                <div class={`${name}__body`}>{content || defaultSlot()}</div>
+                {footer || footerSlot()}
+              </div>
+            </t-popup>
+          </div>
+        )
+      );
     };
   },
 });
-</script>
diff --git a/src/dropdown-menu/dropdown-menu.vue b/src/dropdown-menu/dropdown-menu.tsx
similarity index 82%
rename from src/dropdown-menu/dropdown-menu.vue
rename to src/dropdown-menu/dropdown-menu.tsx
index e0c27233..df42c659 100644
--- a/src/dropdown-menu/dropdown-menu.vue
+++ b/src/dropdown-menu/dropdown-menu.tsx
@@ -1,18 +1,4 @@
-<template>
-  <div ref="refBar" :class="classes">
-    <div v-for="(item, idx) in menuTitles" :key="idx" :class="styleBarItem(item, idx)" @click="expandMenu(item, idx)">
-      <div :class="`${name}__title`">
-        {{ item.label }}
-      </div>
-      <caret-down-small-icon v-if="$props.direction === 'down'" :class="styleIcon(item, idx)" />
-      <caret-up-small-icon v-else :class="styleIcon(item, idx)" />
-    </div>
-    <slot />
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, computed, toRefs, ref, reactive, watch, provide } from 'vue';
+import { defineComponent, computed, ref, reactive, watch, provide } from 'vue';
 
 import { CaretDownSmallIcon, CaretUpSmallIcon } from 'tdesign-icons-vue-next';
 import camelCase from 'lodash/camelCase';
@@ -27,6 +13,7 @@ import {
 } from './context';
 import { useExpose } from '../shared';
 import { findRelativeRect, findRelativeContainer } from './dom-utils';
+import { useContent } from '../hooks/tnode';
 import DropdownMenuProps from './props';
 
 const { prefix } = config;
@@ -38,6 +25,8 @@ export default defineComponent({
   props: DropdownMenuProps,
   emits: ['menuOpened', 'menuClosed'],
   setup(props, { slots }) {
+    const renderContent = useContent();
+
     // 菜单状态
     const state = reactive<DropdownMenuState>({
       activeId: null,
@@ -93,7 +82,7 @@ export default defineComponent({
     // 根结点样式
     const classes = computed(() => [`${name}`]);
     // 标题栏结点引用
-    const refBar = ref(null);
+    const refBar = ref();
     const styleBarItem = computed(() => (item: any, idx: number) => [
       `${name}__item`,
       {
@@ -169,18 +158,27 @@ export default defineComponent({
       collapseMenu,
     });
 
-    return {
-      name: ref(name),
-      classes,
-      ...toRefs(props),
-      refBar,
-      state,
-      styleBarItem,
-      styleIcon,
-      menuItems,
-      menuTitles,
-      expandMenu,
+    return () => {
+      const defaultSlot = renderContent('default', 'content');
+
+      const renderDownIcon = (item: any, idx: number) => {
+        if (props.direction === 'down') {
+          return <caret-down-small-icon class={styleIcon.value(item, idx)} />;
+        }
+        return <caret-up-small-icon class={styleIcon.value(item, idx)} />;
+      };
+
+      return (
+        <div ref={refBar} class={classes.value}>
+          {(menuTitles.value || []).map((item: { label: any }, idx: number) => (
+            <div class={styleBarItem.value(item, idx)} onClick={() => expandMenu(item, idx)}>
+              <div class={`${name}__title`}>{item.label}</div>
+              {renderDownIcon(item, idx)}
+            </div>
+          ))}
+          {defaultSlot}
+        </div>
+      );
     };
   },
 });
-</script>
diff --git a/src/dropdown-menu/index.ts b/src/dropdown-menu/index.ts
index 7276fce2..ff02c353 100644
--- a/src/dropdown-menu/index.ts
+++ b/src/dropdown-menu/index.ts
@@ -1,5 +1,5 @@
-import LocalDropdownMenu from './dropdown-menu.vue';
-import LocalDropdownItem from './dropdown-item.vue';
+import LocalDropdownMenu from './dropdown-menu';
+import LocalDropdownItem from './dropdown-item';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/empty/empty.tsx b/src/empty/empty.tsx
new file mode 100644
index 00000000..05337f16
--- /dev/null
+++ b/src/empty/empty.tsx
@@ -0,0 +1,49 @@
+import { defineComponent } from 'vue';
+import TImage from '../image';
+import EmptyProps from './props';
+import config from '../config';
+
+import { usePrefixClass } from '@/hooks/useClass';
+import { useTNodeJSX } from '../hooks/tnode';
+
+const { prefix } = config;
+const name = `${prefix}-empty`;
+
+export default defineComponent({
+  name,
+  props: EmptyProps,
+  setup(props) {
+    const renderTNodeJSX = useTNodeJSX();
+    const emptyClass = usePrefixClass('empty');
+
+    return () => {
+      const action = renderTNodeJSX('action');
+      const description = renderTNodeJSX('description');
+
+      const readerThumb = () => {
+        const image = renderTNodeJSX('image');
+        if (image) {
+          if (typeof props.image === 'string') {
+            return <TImage v-if="typeof image === 'string'" src={props.image} />;
+          }
+          return image;
+        }
+
+        const icon = renderTNodeJSX('icon');
+        if (icon) {
+          return <div class={`${emptyClass.value}__icon`}>{icon}</div>;
+        }
+        return null;
+      };
+
+      return (
+        <div class={emptyClass.value}>
+          <div class={`${emptyClass.value}__thumb`}>{readerThumb()}</div>
+
+          {description && <div class={`${emptyClass.value}__description`}>{description}</div>}
+          {action && <div class={`${emptyClass.value}__actions`}>{action}</div>}
+        </div>
+      );
+    };
+  },
+});
diff --git a/src/empty/empty.vue b/src/empty/empty.vue
deleted file mode 100644
index 8bc4ada1..00000000
--- a/src/empty/empty.vue
+++ /dev/null
@@ -1,55 +0,0 @@
-<template>
-  <div :class="classPrefix">
-    <div :class="`${classPrefix}__thumb`">
-      <template v-if="imageContent">
-        <t-image v-if="typeof image === 'string'" :src="image" />
-        <t-node v-else :content="imageContent" />
-      </template>
-
-      <div v-else-if="iconContent" :class="`${classPrefix}__icon`">
-        <t-node :content="iconContent" />
-      </div>
-    </div>
-
-    <div v-if="descriptionContent" :class="`${classPrefix}__description`">
-      <t-node :content="descriptionContent" />
-    </div>
-    <div v-if="actionContent" :class="`${classPrefix}__actions`">
-      <t-node :content="actionContent" />
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { toRefs, defineComponent, getCurrentInstance, computed } from 'vue';
-import TImage from '../image';
-import EmptyProps from './props';
-import config from '../config';
-import { renderTNode, TNode } from '../shared';
-
-const { prefix } = config;
-const name = `${prefix}-empty`;
-
-export default defineComponent({
-  name,
-  components: { TNode, TImage },
-
-  props: EmptyProps,
-  setup(props, context) {
-    const internalInstance = getCurrentInstance();
-    const actionContent = computed(() => renderTNode(internalInstance, 'action'));
-    const descriptionContent = computed(() => renderTNode(internalInstance, 'description'));
-    const iconContent = computed(() => renderTNode(internalInstance, 'icon'));
-    const imageContent = computed(() => renderTNode(internalInstance, 'image'));
-
-    return {
-      actionContent,
-      descriptionContent,
-      iconContent,
-      imageContent,
-      classPrefix: name,
-      ...toRefs(props),
-    };
-  },
-});
-</script>
diff --git a/src/empty/index.ts b/src/empty/index.ts
index 5a394049..cf7001f1 100644
--- a/src/empty/index.ts
+++ b/src/empty/index.ts
@@ -1,4 +1,4 @@
-import Empty from './empty.vue';
+import Empty from './empty';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/overlay/index.ts b/src/overlay/index.ts
index 863e551d..c5108139 100644
--- a/src/overlay/index.ts
+++ b/src/overlay/index.ts
@@ -1,7 +1,10 @@
+import _Overlay from './overlay';
 import { withInstall, WithInstallType } from '../shared';
-import _Overlay from './overlay.vue';
 
+import { TdOverlayProps } from './type';
 import './style';
 
+export type OverlayProps = TdOverlayProps;
+
 const Overlay: WithInstallType<typeof _Overlay> = withInstall(_Overlay);
 export default Overlay;
diff --git a/src/overlay/overlay.en-US.md b/src/overlay/overlay.en-US.md
index f7525bd2..ababc086 100644
--- a/src/overlay/overlay.en-US.md
+++ b/src/overlay/overlay.en-US.md
@@ -1,6 +1,7 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Overlay Props
 
 name | type | default | description | required
@@ -19,11 +20,11 @@ name | params | description
 -- | -- | --
 click | `(context: { e: MouseEvent })` | \-
 
+### CSS 变量
 
-### CSS Variables
 The component provides the following CSS variables, which can be used to customize styles.
 Name | Default Value | Description 
 -- | -- | --
 --td-overlay-bg-color | @font-gray-1 | - 
 --td-overlay-transition-duration | 300ms | - 
---td-overlay-zindex | 1000 | - 
+--td-overlay-zindex | 1000 | -
\ No newline at end of file
diff --git a/src/overlay/overlay.md b/src/overlay/overlay.md
index 29f2523e..48dc8a65 100644
--- a/src/overlay/overlay.md
+++ b/src/overlay/overlay.md
@@ -1,11 +1,12 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Overlay Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
-backgroundColor | String | - | 遮罩层的背景色	 | N
+backgroundColor | String | - | 遮罩层的背景色 | N
 customStyle | String | - | 遮罩层自定义样式。优先级低于其他属性 | N
 duration | Number | 300 | 背景色过渡时间，单位毫秒 | N
 preventScrollThrough | Boolean | true | 是否阻止背景滚动，阻止时蒙层里的内容也将无法滚动 | N
@@ -19,11 +20,11 @@ onClick | Function |  | TS 类型：`(context: { e: MouseEvent }) => void`<br/>
 -- | -- | --
 click | `(context: { e: MouseEvent })` | 遮罩层的点击事件
 
-
 ### CSS 变量
+
 组件提供了下列 CSS 变量，可用于自定义样式。
 名称 | 默认值 | 描述 
 -- | -- | --
 --td-overlay-bg-color | @font-gray-1 | - 
 --td-overlay-transition-duration | 300ms | - 
---td-overlay-zindex | 1000 | - 
+--td-overlay-zindex | 1000 | -
\ No newline at end of file
diff --git a/src/overlay/overlay.vue b/src/overlay/overlay.tsx
similarity index 50%
rename from src/overlay/overlay.vue
rename to src/overlay/overlay.tsx
index c5b7566c..99ebd9f4 100644
--- a/src/overlay/overlay.vue
+++ b/src/overlay/overlay.tsx
@@ -1,30 +1,26 @@
-<template>
-  <Transition :name="name">
-    <div v-show="visible" :class="classes" :style="rootStyles" @click="handleClick" @touchmove="handleTouchMove">
-      <slot />
-    </div>
-  </Transition>
-</template>
-
-<script lang="ts">
-import { computed, defineComponent } from 'vue';
+import { Transition, computed, defineComponent } from 'vue';
 import { preventDefault } from '../shared/dom';
 import config from '../config';
-import props from './props';
+import OverlayProps from './props';
+import { usePrefixClass } from '../hooks/useClass';
+import { useTNodeJSX } from '../hooks/tnode';
 
 const { prefix } = config;
 const name = `${prefix}-overlay`;
 
 export default defineComponent({
   name,
-  props,
+  props: OverlayProps,
   setup(props) {
-    const classes = computed(() => ({
-      [`${name}`]: true,
-      [`${name}--active`]: props.visible,
+    const renderTNodeJSX = useTNodeJSX();
+    const overlayClass = usePrefixClass('overlay');
+
+    const overlayClasses = computed(() => ({
+      [`${overlayClass.value}`]: true,
+      [`${overlayClass.value}--active`]: props.visible,
     }));
 
-    const rootStyles = computed(() => {
+    const overlayStyles = computed(() => {
       const arr = [];
 
       if (props.customStyle) {
@@ -51,13 +47,18 @@ export default defineComponent({
       props.onClick?.({ e });
     };
 
-    return {
-      name,
-      classes,
-      rootStyles,
-      handleClick,
-      handleTouchMove,
-    };
+    return () => (
+      <Transition name={name}>
+        <div
+          v-show={props.visible}
+          class={overlayClasses.value}
+          style={overlayStyles.value}
+          onClick={handleClick}
+          onTouchmove={handleTouchMove}
+        >
+          {renderTNodeJSX('default')}
+        </div>
+      </Transition>
+    );
   },
 });
-</script>
diff --git a/src/overlay/props.ts b/src/overlay/props.ts
index 41048125..0c008905 100644
--- a/src/overlay/props.ts
+++ b/src/overlay/props.ts
@@ -8,7 +8,7 @@ import { TdOverlayProps } from './type';
 import { PropType } from 'vue';
 
 export default {
-  /** 遮罩层的背景色	 */
+  /** 遮罩层的背景色 */
   backgroundColor: {
     type: String,
     default: '',
@@ -23,7 +23,7 @@ export default {
     type: Number,
     default: 300,
   },
-  /** 防止滚动穿透，即不允许点击和滚动 */
+  /** 是否阻止背景滚动，阻止时蒙层里的内容也将无法滚动 */
   preventScrollThrough: {
     type: Boolean,
     default: true,
diff --git a/src/overlay/type.ts b/src/overlay/type.ts
index 809f61c1..e51d7cc6 100644
--- a/src/overlay/type.ts
+++ b/src/overlay/type.ts
@@ -21,7 +21,7 @@ export interface TdOverlayProps {
    */
   duration?: number;
   /**
-   * 防止滚动穿透，即不允许点击和滚动
+   * 是否阻止背景滚动，阻止时蒙层里的内容也将无法滚动
    * @default true
    */
   preventScrollThrough?: boolean;
diff --git a/src/side-bar/side-bar-item.vue b/src/side-bar/side-bar-item.vue
index 72febe70..caefe786 100644
--- a/src/side-bar/side-bar-item.vue
+++ b/src/side-bar/side-bar-item.vue
@@ -14,10 +14,11 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, getCurrentInstance, ComponentInternalInstance, computed, inject, onUnmounted } from 'vue';
+import { defineComponent, getCurrentInstance, ComponentPublicInstance, computed, inject, onUnmounted } from 'vue';
 import TBadge from '../badge';
 import { renderTNode, TNode } from '../shared';
 import SideBarItemProps from './side-bar-item-props';
+import { TdSideBarItemProps } from './type';
 
 import config from '../config';
 
@@ -30,13 +31,12 @@ export default defineComponent({
   props: SideBarItemProps,
   setup(props) {
     const internalInstance = getCurrentInstance();
-    const { proxy } = internalInstance as ComponentInternalInstance;
+    const proxy = internalInstance.proxy as ComponentPublicInstance<TdSideBarItemProps>;
     const sideBarProvide: any = inject('sideBarProvide', undefined);
     sideBarProvide.relation(proxy);
 
-    const index = computed(() => sideBarProvide.children.value.indexOf(proxy));
     const iconNode = computed(() => renderTNode(internalInstance, 'icon'));
-    const isActive = computed(() => index.value === sideBarProvide.currentValue.value);
+    const isActive = computed(() => proxy.value === sideBarProvide.currentValue.value);
 
     const rootClassName = computed(() => [
       name,
@@ -45,7 +45,7 @@ export default defineComponent({
     ]);
 
     const onClick = (e: MouseEvent) => {
-      sideBarProvide.onClickItem(index.value, props.label);
+      sideBarProvide.onClickItem(proxy.value, props.label);
     };
 
     onUnmounted(() => {
diff --git a/src/sticky/index.ts b/src/sticky/index.ts
index 3638941f..8207a614 100644
--- a/src/sticky/index.ts
+++ b/src/sticky/index.ts
@@ -1,4 +1,4 @@
-import Sticky from './sticky.vue';
+import Sticky from './sticky';
 import { withInstall, WithInstallType } from '../shared';
 import { TdStickyProps } from './type';
 
diff --git a/src/sticky/props.ts b/src/sticky/props.ts
index f597a536..69060e1a 100644
--- a/src/sticky/props.ts
+++ b/src/sticky/props.ts
@@ -8,7 +8,7 @@ import { TdStickyProps } from './type';
 import { PropType } from 'vue';
 
 export default {
-  /** 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置。 */
+  /** 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置 */
   container: {
     type: Object as PropType<TdStickyProps['container']>,
   },
diff --git a/src/sticky/sticky.en-US.md b/src/sticky/sticky.en-US.md
index 86c1cc3d..1a1bb399 100644
--- a/src/sticky/sticky.en-US.md
+++ b/src/sticky/sticky.en-US.md
@@ -6,7 +6,7 @@
 
 name | type | default | description | required
 -- | -- | -- | -- | --
-container | Object | - | | N
+container | Object | - | Typescript：`Element` | N
 disabled | Boolean | false | \- | N
 offsetTop | String / Number | 0 | \- | N
 zIndex | Number | 99 | \- | N
diff --git a/src/sticky/sticky.md b/src/sticky/sticky.md
index 3d00b684..37188d1a 100644
--- a/src/sticky/sticky.md
+++ b/src/sticky/sticky.md
@@ -1,11 +1,12 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Sticky Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
-container | Object | - | 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置。。TS 类型：`Element` | N
+container | Object | - | 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置。TS 类型：`Element` | N
 disabled | Boolean | false | 是否禁用组件 | N
 offsetTop | String / Number | 0 | 吸顶时与顶部的距离，单位`px` | N
 zIndex | Number | 99 | 吸顶时的 z-index | N
diff --git a/src/sticky/sticky.vue b/src/sticky/sticky.tsx
similarity index 62%
rename from src/sticky/sticky.vue
rename to src/sticky/sticky.tsx
index 0fccbc75..5beadda2 100644
--- a/src/sticky/sticky.vue
+++ b/src/sticky/sticky.tsx
@@ -1,36 +1,27 @@
-<template>
-  <div ref="boxRef" :class="boxClasses" :style="boxStyles">
-    <div ref="contentRef" :class="`${boxClasses}__content`" :style="contentStyles">
-      <t-node :content="stickyContent"></t-node>
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-import { computed, getCurrentInstance, defineComponent, ref, watch } from 'vue';
-import { useElementBounding, templateRef } from '@vueuse/core';
-import props from './props';
+import { computed, defineComponent, ref, watch } from 'vue';
+import { useElementBounding } from '@vueuse/core';
+import StickyProps from './props';
 import config from '../config';
-import { renderContent, TNode } from '../shared';
+import { usePrefixClass } from '@/hooks/useClass';
+import { useTNodeJSX } from '@/hooks/tnode';
 
 const name = `${config.prefix}-sticky`;
 
 export default defineComponent({
   name,
-  components: { TNode },
-  props,
+  props: StickyProps,
   setup(props) {
-    const boxClasses = name;
-    const internalInstance = getCurrentInstance();
-    const stickyContent = computed(() => renderContent(internalInstance, 'default', ''));
+    const renderTNodeJSX = useTNodeJSX();
+    const stickyBarClass = usePrefixClass('sticky');
+
     // box 用于占位和记录边界
     // content 用于实际定位
-    const boxRef = templateRef<HTMLElement | null>('boxRef', null);
+    const boxRef = ref<HTMLElement>();
     const { top: boxTop } = useElementBounding(boxRef);
-    const contentRef = templateRef<HTMLElement | null>('contentRef', null);
+    const contentRef = ref<HTMLElement>();
     const { top: contentTop, height } = useElementBounding(contentRef);
 
-    const boxStyles = computed(() => `height:${height.value}px;`);
+    const stickyStyle = computed(() => `height:${height.value}px;`);
 
     // container 容器，sticky不会超出该边界
     let container: HTMLElement;
@@ -69,12 +60,12 @@ export default defineComponent({
       return styleStr;
     });
 
-    return {
-      boxClasses,
-      boxStyles,
-      contentStyles,
-      stickyContent,
-    };
+    return () => (
+      <div ref={boxRef} class={stickyBarClass.value} style={stickyStyle.value}>
+        <div ref={contentRef} class={`${stickyBarClass.value}__content`} style={contentStyles.value}>
+          {renderTNodeJSX('default')}
+        </div>
+      </div>
+    );
   },
 });
-</script>
diff --git a/src/sticky/type.ts b/src/sticky/type.ts
index dbca4c7e..bd4c8d8c 100644
--- a/src/sticky/type.ts
+++ b/src/sticky/type.ts
@@ -6,7 +6,7 @@
 
 export interface TdStickyProps {
   /**
-   * 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置。
+   * 指定容器对应的NodesRef节点为组件的外部容器，滚动时组件会始终保持在容器范围内，当组件即将超出容器底部时，会返回原位置
    */
   container?: Element;
   /**


Test patch:
diff --git a/src/avatar/__test__/__snapshots__/demo.test.jsx.snap b/src/avatar/__test__/__snapshots__/demo.test.jsx.snap
index e50f969d..44138474 100644
--- a/src/avatar/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/avatar/__test__/__snapshots__/demo.test.jsx.snap
@@ -343,8 +343,50 @@ exports[`Avatar > Avatar actionVue demo works fine 1`] = `
         </div>
       </div>
     </div>
+    <div
+      class="t-avatar__wrapper"
+    >
+      <div
+        class="t-avatar__badge"
+      >
+        <div
+          class="t-badge"
+        >
+          <div
+            class="t-badge__content"
+          >
+            
+            <div
+              class="t-avatar t-avatar--medium t-avatar--circle t-avatar--border t-avatar--border-medium"
+            >
+              <span>
+                
+                
+                <svg
+                  class="t-icon t-icon-user-add"
+                  fill="none"
+                  height="1em"
+                  style="font-size: 24px;"
+                  viewBox="0 0 24 24"
+                  width="1em"
+                >
+                  <path
+                    d="M11.5 4a3.5 3.5 0 100 7 3.5 3.5 0 000-7zM6 7.5a5.5 5.5 0 1111 0 5.5 5.5 0 01-11 0zM19 13v4h4v2h-4v4h-2v-4h-4v-2h4v-4h2zM8 16a4 4 0 00-4 4h8.05v2H2v-2a6 6 0 016-6h4v2H8z"
+                    fill="currentColor"
+                  />
+                </svg>
+                
+                
+              </span>
+            </div>
+            
+          </div>
+          <!---->
+          <!---->
+        </div>
+      </div>
+    </div>
     
-    <!--v-if-->
   </div>
 </div>
 `;
@@ -927,8 +969,36 @@ exports[`Avatar > Avatar exhibitionVue demo works fine 1`] = `
         </div>
       </div>
     </div>
+    <div
+      class="t-avatar__wrapper"
+    >
+      <div
+        class="t-avatar__badge"
+      >
+        <div
+          class="t-badge"
+        >
+          <div
+            class="t-badge__content"
+          >
+            
+            <div
+              class="t-avatar t-avatar--medium t-avatar--circle t-avatar--border t-avatar--border-medium"
+            >
+              <span>
+                
+                +5
+                
+              </span>
+            </div>
+            
+          </div>
+          <!---->
+          <!---->
+        </div>
+      </div>
+    </div>
     
-    <!--v-if-->
   </div>
 </div>
 `;
@@ -1903,8 +1973,36 @@ exports[`Avatar > Avatar mobileVue demo works fine 1`] = `
               </div>
             </div>
           </div>
+          <div
+            class="t-avatar__wrapper"
+          >
+            <div
+              class="t-avatar__badge"
+            >
+              <div
+                class="t-badge"
+              >
+                <div
+                  class="t-badge__content"
+                >
+                  
+                  <div
+                    class="t-avatar t-avatar--medium t-avatar--circle t-avatar--border t-avatar--border-medium"
+                  >
+                    <span>
+                      
+                      +5
+                      
+                    </span>
+                  </div>
+                  
+                </div>
+                <!---->
+                <!---->
+              </div>
+            </div>
+          </div>
           
-          <!--v-if-->
         </div>
       </div>
       
@@ -2271,8 +2369,50 @@ exports[`Avatar > Avatar mobileVue demo works fine 1`] = `
               </div>
             </div>
           </div>
+          <div
+            class="t-avatar__wrapper"
+          >
+            <div
+              class="t-avatar__badge"
+            >
+              <div
+                class="t-badge"
+              >
+                <div
+                  class="t-badge__content"
+                >
+                  
+                  <div
+                    class="t-avatar t-avatar--medium t-avatar--circle t-avatar--border t-avatar--border-medium"
+                  >
+                    <span>
+                      
+                      
+                      <svg
+                        class="t-icon t-icon-user-add"
+                        fill="none"
+                        height="1em"
+                        style="font-size: 24px;"
+                        viewBox="0 0 24 24"
+                        width="1em"
+                      >
+                        <path
+                          d="M11.5 4a3.5 3.5 0 100 7 3.5 3.5 0 000-7zM6 7.5a5.5 5.5 0 1111 0 5.5 5.5 0 01-11 0zM19 13v4h4v2h-4v4h-2v-4h-4v-2h4v-4h2zM8 16a4 4 0 00-4 4h8.05v2H2v-2a6 6 0 016-6h4v2H8z"
+                          fill="currentColor"
+                        />
+                      </svg>
+                      
+                      
+                    </span>
+                  </div>
+                  
+                </div>
+                <!---->
+                <!---->
+              </div>
+            </div>
+          </div>
           
-          <!--v-if-->
         </div>
       </div>
       
diff --git a/src/avatar/__test__/index.test.jsx b/src/avatar/__test__/index.test.jsx
index b23dbfc9..1724326b 100644
--- a/src/avatar/__test__/index.test.jsx
+++ b/src/avatar/__test__/index.test.jsx
@@ -2,8 +2,8 @@ import { h, nextTick } from 'vue';
 import { mount } from '@vue/test-utils';
 import { describe, it, expect, vi } from 'vitest';
 import { UserIcon } from 'tdesign-icons-vue-next';
-import Avatar from '../avatar.vue';
-import AvatarGroup from '../avatar-group.vue';
+import Avatar from '../avatar';
+import AvatarGroup from '../avatar-group';
 import Badge from '../../badge/badge';
 
 const IMAGE = 'https://tdesign.gtimg.com/site/avatar.jpg';
@@ -121,7 +121,7 @@ describe('avatar-group', async () => {
 
   it(': max', async () => {
     const wrapper = mount(() => (
-      <AvatarGroup max={1}>
+      <AvatarGroup max={2}>
         <Avatar image={IMAGE}></Avatar>
         <Avatar image={IMAGE}></Avatar>
         <Avatar image={IMAGE}></Avatar>
@@ -130,6 +130,7 @@ describe('avatar-group', async () => {
       </AvatarGroup>
     ));
     const avatarList = wrapper.findAllComponents(Avatar);
-    expect(avatarList.length).toBe(1);
+    expect(avatarList.length).toBe(3);
+    expect(avatarList[avatarList.length-1].text()).toBe('+3');
   });
 });
diff --git a/src/calendar/__test__/__snapshots__/demo.test.jsx.snap b/src/calendar/__test__/__snapshots__/demo.test.jsx.snap
index e56b936b..413579be 100644
--- a/src/calendar/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/calendar/__test__/__snapshots__/demo.test.jsx.snap
@@ -11,8 +11,7 @@ exports[`Calendar > Calendar baseVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
@@ -2204,8 +2203,7 @@ exports[`Calendar > Calendar customButtonVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
@@ -4398,8 +4396,7 @@ exports[`Calendar > Calendar customRangeVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
@@ -4858,8 +4855,7 @@ exports[`Calendar > Calendar customTextVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
@@ -5869,8 +5865,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
                 class="t-overlay"
                 style="z-index: 1000; transition-duration: 300ms; display: none;"
               >
-                
-                
+                <!---->
               </div>
               <div
                 class="t-popup t-popup--bottom"
@@ -8056,8 +8051,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
                 class="t-overlay"
                 style="z-index: 1000; transition-duration: 300ms; display: none;"
               >
-                
-                
+                <!---->
               </div>
               <div
                 class="t-popup t-popup--bottom"
@@ -10243,8 +10237,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
                 class="t-overlay"
                 style="z-index: 1000; transition-duration: 300ms; display: none;"
               >
-                
-                
+                <!---->
               </div>
               <div
                 class="t-popup t-popup--bottom"
@@ -12455,8 +12448,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--bottom"
@@ -13429,8 +13421,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--bottom"
@@ -15616,8 +15607,7 @@ exports[`Calendar > Calendar mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--bottom"
@@ -18193,8 +18183,7 @@ exports[`Calendar > Calendar multipleVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
@@ -20383,8 +20372,7 @@ exports[`Calendar > Calendar rangeVue demo works fine 1`] = `
         class="t-overlay"
         style="z-index: 1000; transition-duration: 300ms; display: none;"
       >
-        
-        
+        <!---->
       </div>
       <div
         class="t-popup t-popup--bottom"
diff --git a/src/calendar/__test__/__snapshots__/index.test.jsx.snap b/src/calendar/__test__/__snapshots__/index.test.jsx.snap
index 9447e3ac..95b228c6 100644
--- a/src/calendar/__test__/__snapshots__/index.test.jsx.snap
+++ b/src/calendar/__test__/__snapshots__/index.test.jsx.snap
@@ -10,8 +10,7 @@ exports[`calendar > props > : format 1`] = `
       class="t-overlay t-overlay--active"
       style="z-index: 1000; transition-duration: 300ms;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
diff --git a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap
index 6b7fe1da..d762da07 100644
--- a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap
@@ -55,8 +55,7 @@ exports[`Cascader > Cascader baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -287,8 +286,7 @@ exports[`Cascader > Cascader checkStrictlyVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -512,8 +510,7 @@ exports[`Cascader > Cascader keysVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -742,8 +739,7 @@ exports[`Cascader > Cascader lazyVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -969,8 +965,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1212,8 +1207,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1428,8 +1422,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1671,8 +1664,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1914,8 +1906,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -2161,8 +2152,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -2372,8 +2362,7 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -2600,8 +2589,7 @@ exports[`Cascader > Cascader themeTabVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -2799,8 +2787,7 @@ exports[`Cascader > Cascader withTitleVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -3033,8 +3020,7 @@ exports[`Cascader > Cascader withValueVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
diff --git a/src/cascader/__test__/__snapshots__/index.test.jsx.snap b/src/cascader/__test__/__snapshots__/index.test.jsx.snap
index 77396bef..d6061946 100644
--- a/src/cascader/__test__/__snapshots__/index.test.jsx.snap
+++ b/src/cascader/__test__/__snapshots__/index.test.jsx.snap
@@ -9,8 +9,7 @@ exports[`cascader > events > : pick 1`] = `
     class="t-overlay"
     style="z-index: 1000; transition-duration: 300ms; display: none;"
   >
-    
-    
+    <!---->
   </div>
   <div
     class="t-popup t-popup--bottom"
diff --git a/src/cell/__test__/index.test.jsx b/src/cell/__test__/index.test.jsx
index ba0275d3..772d84a3 100644
--- a/src/cell/__test__/index.test.jsx
+++ b/src/cell/__test__/index.test.jsx
@@ -4,7 +4,7 @@ import { describe, it, expect } from 'vitest';
 import { ChevronRightIcon, AppIcon } from 'tdesign-icons-vue-next';
 import Cell from '../cell';
 import CellGroup from '../cell-group';
-import Avatar from '../../avatar/avatar.vue';
+import Avatar from '../../avatar/avatar';
 
 const appIcon = () => h(AppIcon);
 const chevronRightIcon = () => h(ChevronRightIcon);
diff --git a/src/date-time-picker/__test__/__snapshots__/demo.test.jsx.snap b/src/date-time-picker/__test__/__snapshots__/demo.test.jsx.snap
index c5ab9501..95152429 100644
--- a/src/date-time-picker/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/date-time-picker/__test__/__snapshots__/demo.test.jsx.snap
@@ -36,8 +36,7 @@ exports[`DateTimePicker > DateTimePicker baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -475,8 +474,7 @@ exports[`DateTimePicker > DateTimePicker customRangeVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -844,8 +842,7 @@ exports[`DateTimePicker > DateTimePicker fullVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -2072,8 +2069,7 @@ exports[`DateTimePicker > DateTimePicker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -2504,8 +2500,7 @@ exports[`DateTimePicker > DateTimePicker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -2775,8 +2770,7 @@ exports[`DateTimePicker > DateTimePicker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -3325,8 +3319,7 @@ exports[`DateTimePicker > DateTimePicker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -3697,8 +3690,7 @@ exports[`DateTimePicker > DateTimePicker timeVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -4230,8 +4222,7 @@ exports[`DateTimePicker > DateTimePicker yearMonthVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
diff --git a/src/dialog/__test__/__snapshots__/demo.test.jsx.snap b/src/dialog/__test__/__snapshots__/demo.test.jsx.snap
index bc9bcc84..eb0bdd52 100644
--- a/src/dialog/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/dialog/__test__/__snapshots__/demo.test.jsx.snap
@@ -29,8 +29,7 @@ exports[`Dialog > Dialog confirmVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -134,8 +133,7 @@ exports[`Dialog > Dialog confirmVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -241,8 +239,7 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -333,8 +330,7 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -421,8 +417,7 @@ exports[`Dialog > Dialog feedbackVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -523,8 +518,7 @@ exports[`Dialog > Dialog imageDialogVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -675,8 +669,7 @@ exports[`Dialog > Dialog imageDialogVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -832,8 +825,7 @@ exports[`Dialog > Dialog inputVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -980,8 +972,7 @@ exports[`Dialog > Dialog inputVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -1167,8 +1158,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1259,8 +1249,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1347,8 +1336,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1460,8 +1448,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1565,8 +1552,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1687,8 +1673,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -1835,8 +1820,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2006,8 +1990,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2158,8 +2141,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2330,8 +2312,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2435,8 +2416,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2540,8 +2520,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2645,8 +2624,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2767,8 +2745,7 @@ exports[`Dialog > Dialog mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--center"
@@ -2934,8 +2911,7 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -3039,8 +3015,7 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -3144,8 +3119,7 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -3249,8 +3223,7 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -3371,8 +3344,7 @@ exports[`Dialog > Dialog multiStateVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
diff --git a/src/drawer/__test__/__snapshots__/demo.test.jsx.snap b/src/drawer/__test__/__snapshots__/demo.test.jsx.snap
index fce62cda..e3decdf3 100644
--- a/src/drawer/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/drawer/__test__/__snapshots__/demo.test.jsx.snap
@@ -13,8 +13,7 @@ exports[`Drawer > Drawer baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--right"
@@ -136,8 +135,7 @@ exports[`Drawer > Drawer footerVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--left"
@@ -281,8 +279,7 @@ exports[`Drawer > Drawer iconVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--right"
@@ -530,8 +527,7 @@ exports[`Drawer > Drawer mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--right"
@@ -668,8 +664,7 @@ exports[`Drawer > Drawer mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--right"
@@ -900,8 +895,7 @@ exports[`Drawer > Drawer mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--left"
@@ -1041,8 +1035,7 @@ exports[`Drawer > Drawer mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--left"
@@ -1249,8 +1242,7 @@ exports[`Drawer > Drawer titleVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--left"
diff --git a/src/dropdown-menu/__test__/__snapshots__/demo.test.jsx.snap b/src/dropdown-menu/__test__/__snapshots__/demo.test.jsx.snap
index af942bb1..15225d5c 100644
--- a/src/dropdown-menu/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/dropdown-menu/__test__/__snapshots__/demo.test.jsx.snap
@@ -29,7 +29,7 @@ exports[`DropdownMenu > DropdownMenu customizedVue demo works fine 1`] = `
   </div>
   
   
-  <!--v-if-->
+  <!---->
   
 </div>
 `;
@@ -83,8 +83,8 @@ exports[`DropdownMenu > DropdownMenu directionVue demo works fine 1`] = `
   </div>
   
   
-  <!--v-if-->
-  <!--v-if-->
+  <!---->
+  <!---->
   
 </div>
 `;
@@ -138,8 +138,8 @@ exports[`DropdownMenu > DropdownMenu disabledVue demo works fine 1`] = `
   </div>
   
   
-  <!--v-if-->
-  <!--v-if-->
+  <!---->
+  <!---->
   
 </div>
 `;
@@ -232,8 +232,8 @@ exports[`DropdownMenu > DropdownMenu mobileVue demo works fine 1`] = `
         </div>
         
         
-        <!--v-if-->
-        <!--v-if-->
+        <!---->
+        <!---->
         
       </div>
       
@@ -327,9 +327,9 @@ exports[`DropdownMenu > DropdownMenu mobileVue demo works fine 1`] = `
         </div>
         
         
-        <!--v-if-->
-        <!--v-if-->
-        <!--v-if-->
+        <!---->
+        <!---->
+        <!---->
         
       </div>
       
@@ -402,8 +402,8 @@ exports[`DropdownMenu > DropdownMenu mobileVue demo works fine 1`] = `
         </div>
         
         
-        <!--v-if-->
-        <!--v-if-->
+        <!---->
+        <!---->
         
       </div>
       
@@ -480,8 +480,8 @@ exports[`DropdownMenu > DropdownMenu mobileVue demo works fine 1`] = `
         </div>
         
         
-        <!--v-if-->
-        <!--v-if-->
+        <!---->
+        <!---->
         
       </div>
       
@@ -534,7 +534,7 @@ exports[`DropdownMenu > DropdownMenu mobileVue demo works fine 1`] = `
         </div>
         
         
-        <!--v-if-->
+        <!---->
         
       </div>
       
@@ -617,9 +617,9 @@ exports[`DropdownMenu > DropdownMenu multipleVue demo works fine 1`] = `
   </div>
   
   
-  <!--v-if-->
-  <!--v-if-->
-  <!--v-if-->
+  <!---->
+  <!---->
+  <!---->
   
 </div>
 `;
@@ -673,8 +673,8 @@ exports[`DropdownMenu > DropdownMenu singleVue demo works fine 1`] = `
   </div>
   
   
-  <!--v-if-->
-  <!--v-if-->
+  <!---->
+  <!---->
   
 </div>
 `;
diff --git a/src/empty/__test__/__snapshots__/demo.test.jsx.snap b/src/empty/__test__/__snapshots__/demo.test.jsx.snap
index 7ec2355f..330073d9 100644
--- a/src/empty/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/empty/__test__/__snapshots__/demo.test.jsx.snap
@@ -29,7 +29,7 @@ exports[`Empty > Empty baseVue demo works fine 1`] = `
   >
     描述文字
   </div>
-  <!--v-if-->
+  <!---->
 </div>
 `;
 
@@ -94,7 +94,6 @@ exports[`Empty > Empty imageEmptyVue demo works fine 1`] = `
   <div
     class="t-empty__thumb"
   >
-    
     <div
       class="t-image t-image--square"
     >
@@ -138,14 +137,13 @@ exports[`Empty > Empty imageEmptyVue demo works fine 1`] = `
         />
       </picture>
     </div>
-    
   </div>
   <div
     class="t-empty__description"
   >
     描述文字
   </div>
-  <!--v-if-->
+  <!---->
 </div>
 `;
 
@@ -208,7 +206,7 @@ exports[`Empty > Empty mobileVue demo works fine 1`] = `
         >
           描述文字
         </div>
-        <!--v-if-->
+        <!---->
       </div>
       
     </div>
@@ -236,7 +234,6 @@ exports[`Empty > Empty mobileVue demo works fine 1`] = `
         <div
           class="t-empty__thumb"
         >
-          
           <div
             class="t-image t-image--square"
           >
@@ -280,14 +277,13 @@ exports[`Empty > Empty mobileVue demo works fine 1`] = `
               />
             </picture>
           </div>
-          
         </div>
         <div
           class="t-empty__description"
         >
           描述文字
         </div>
-        <!--v-if-->
+        <!---->
       </div>
       
     </div>
diff --git a/src/form/__test__/__snapshots__/demo.test.jsx.snap b/src/form/__test__/__snapshots__/demo.test.jsx.snap
index b8cf5bb9..5ae73707 100644
--- a/src/form/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/form/__test__/__snapshots__/demo.test.jsx.snap
@@ -392,8 +392,7 @@ exports[`Form > Form horizontalVue demo works fine 1`] = `
               class="t-overlay"
               style="z-index: 1000; transition-duration: 300ms; display: none;"
             >
-              
-              
+              <!---->
             </div>
             <div
               class="t-popup t-popup--bottom"
@@ -826,8 +825,7 @@ exports[`Form > Form horizontalVue demo works fine 1`] = `
               class="t-overlay"
               style="z-index: 1000; transition-duration: 300ms; display: none;"
             >
-              
-              
+              <!---->
             </div>
             <div
               class="t-popup t-popup--bottom"
@@ -2122,8 +2120,7 @@ exports[`Form > Form mobileVue demo works fine 1`] = `
                     class="t-overlay"
                     style="z-index: 1000; transition-duration: 300ms; display: none;"
                   >
-                    
-                    
+                    <!---->
                   </div>
                   <div
                     class="t-popup t-popup--bottom"
@@ -2556,8 +2553,7 @@ exports[`Form > Form mobileVue demo works fine 1`] = `
                     class="t-overlay"
                     style="z-index: 1000; transition-duration: 300ms; display: none;"
                   >
-                    
-                    
+                    <!---->
                   </div>
                   <div
                     class="t-popup t-popup--bottom"
@@ -3715,8 +3711,7 @@ exports[`Form > Form verticalVue demo works fine 1`] = `
               class="t-overlay"
               style="z-index: 1000; transition-duration: 300ms; display: none;"
             >
-              
-              
+              <!---->
             </div>
             <div
               class="t-popup t-popup--bottom"
@@ -4147,8 +4142,7 @@ exports[`Form > Form verticalVue demo works fine 1`] = `
               class="t-overlay"
               style="z-index: 1000; transition-duration: 300ms; display: none;"
             >
-              
-              
+              <!---->
             </div>
             <div
               class="t-popup t-popup--bottom"
diff --git a/src/overlay/__test__/__snapshots__/demo.test.jsx.snap b/src/overlay/__test__/__snapshots__/demo.test.jsx.snap
index 25a5105a..9bc41c74 100644
--- a/src/overlay/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/overlay/__test__/__snapshots__/demo.test.jsx.snap
@@ -25,8 +25,7 @@ exports[`Overlay > Overlay baseVue demo works fine 1`] = `
     class="t-overlay"
     style="z-index: 1000; transition-duration: 300ms; display: none;"
   >
-    
-    
+    <!---->
   </div>
   
 </div>
@@ -91,8 +90,7 @@ exports[`Overlay > Overlay mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         
       </div>
diff --git a/src/overlay/__test__/index.test.jsx b/src/overlay/__test__/index.test.jsx
index d8533324..e5542699 100644
--- a/src/overlay/__test__/index.test.jsx
+++ b/src/overlay/__test__/index.test.jsx
@@ -1,5 +1,5 @@
 import { describe, it, expect, vi } from 'vitest';
-import Overlay from '../overlay.vue';
+import Overlay from '../overlay';
 import { mount } from '@vue/test-utils';
 
 describe('Overlay', () => {
diff --git a/src/picker/__test__/__snapshots__/demo.test.jsx.snap b/src/picker/__test__/__snapshots__/demo.test.jsx.snap
index fb2735d8..eaefccca 100644
--- a/src/picker/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/picker/__test__/__snapshots__/demo.test.jsx.snap
@@ -51,8 +51,7 @@ exports[`Picker > Picker areaVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -241,8 +240,7 @@ exports[`Picker > Picker baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -348,8 +346,7 @@ exports[`Picker > Picker baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -561,8 +558,7 @@ exports[`Picker > Picker cascadeVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
@@ -791,8 +787,7 @@ exports[`Picker > Picker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -898,8 +893,7 @@ exports[`Picker > Picker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1090,8 +1084,7 @@ exports[`Picker > Picker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1294,8 +1287,7 @@ exports[`Picker > Picker mobileVue demo works fine 1`] = `
           class="t-overlay"
           style="z-index: 1000; transition-duration: 300ms; display: none;"
         >
-          
-          
+          <!---->
         </div>
         <div
           class="t-popup t-popup--bottom"
@@ -1476,8 +1468,7 @@ exports[`Picker > Picker titleVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
diff --git a/src/popup/__test__/__snapshots__/demo.test.jsx.snap b/src/popup/__test__/__snapshots__/demo.test.jsx.snap
index ba394989..5b0c8495 100644
--- a/src/popup/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/popup/__test__/__snapshots__/demo.test.jsx.snap
@@ -101,8 +101,7 @@ exports[`Popup > Popup baseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--top"
@@ -144,8 +143,7 @@ exports[`Popup > Popup customCloseVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--center"
@@ -307,8 +305,7 @@ exports[`Popup > Popup mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--top"
@@ -376,8 +373,7 @@ exports[`Popup > Popup mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--bottom"
@@ -442,8 +438,7 @@ exports[`Popup > Popup mobileVue demo works fine 1`] = `
             class="t-overlay"
             style="z-index: 1000; transition-duration: 300ms; display: none;"
           >
-            
-            
+            <!---->
           </div>
           <div
             class="t-popup t-popup--center"
@@ -500,8 +495,7 @@ exports[`Popup > Popup withTitleVue demo works fine 1`] = `
       class="t-overlay"
       style="z-index: 1000; transition-duration: 300ms; display: none;"
     >
-      
-      
+      <!---->
     </div>
     <div
       class="t-popup t-popup--bottom"
diff --git a/src/sticky/__test__/index.test.jsx b/src/sticky/__test__/index.test.jsx
index b8011f53..5ed68ac4 100644
--- a/src/sticky/__test__/index.test.jsx
+++ b/src/sticky/__test__/index.test.jsx
@@ -1,7 +1,7 @@
 import { mount } from '@vue/test-utils';
 import { describe, it, expect, vi } from 'vitest';
 import { nextTick } from 'vue';
-import Sticky from '../sticky.vue';
+import Sticky from '../sticky';
 import { useTestUtils, useVitest } from '../../shared';
 
 const _mount = (template, data = () => ({}), methods = {}) =>