Repository: Tencent/tdesign-mobile-vue
Pull request #1314 (2024-04-17 06:26:54)

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


github-actions[bot]: <a href="https://preview-pr1314-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/8717374058) -->
<!-- AUTO_PREVIEW_HOOK -->
github-actions[bot]: **Size Change:** -1.09 kB (0%) 

**Total Size:** 438 kB

| Filename | Size | Change |
| :--- | :---: | :---: |
| `./dist/tdesign.js` | 234 kB | -699 B (0%) |
| `./dist/tdesign.min.js` | 137 kB | -388 B (0%) |

<details><summary>ℹ️ <strong>View Unchanged</strong></summary>

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |
| `./dist/tdesign.css` | 38.4 kB |
| `./dist/tdesign.min.css` | 28 kB |

</details>



Patch:
diff --git a/.github/workflows/pr-spelling.template.yml b/.github/workflows/pr-spelling.template.yml
index 3e3732ff..d6237cdd 100644
--- a/.github/workflows/pr-spelling.template.yml
+++ b/.github/workflows/pr-spelling.template.yml
@@ -6,7 +6,7 @@ jobs:
     name: Spell Check with Typos
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
       - name: Check spelling
         uses: crate-ci/typos@master
         with:
diff --git a/.github/workflows/typos-config.toml b/.github/workflows/typos-config.toml
index 25243a87..723bfea6 100644
--- a/.github/workflows/typos-config.toml
+++ b/.github/workflows/typos-config.toml
@@ -1,13 +1,8 @@
+default.check-filename = true
+
 [default.extend-words]
 actived = "actived"
-formated = "formated"
-formate = "formate"
-Colum = "Colum"
-ans = "ans"
-ba = "ba"
-ded = "ded"
-Hel = "Hel"
-Successivo = "Successivo"
+colum = "colum"
 
 [files]
 extend-exclude = ["CHANGELOG.md", "*.snap"]
diff --git a/src/button/button.en-US.md b/src/button/button.en-US.md
index 00adaf2d..5f5998ec 100644
--- a/src/button/button.en-US.md
+++ b/src/button/button.en-US.md
@@ -1,6 +1,7 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Button Props
 
 name | type | default | description | required
@@ -12,12 +13,12 @@ ghost | Boolean | false | make background-color to be transparent | N
 icon | Slot / Function | - | use it to set left icon in button。Typescript：`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 loading | Boolean | false | set button to be loading state | N
 loadingProps | Object | - | Typescript：`LoadingProps`，[Loading API Documents](./loading?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/button/type.ts) | N
-shape | String | rectangle | button shape。options：rectangle/square/round/circle | N
-size | String | medium | a button has three size。options：extra-small/small/medium/large。Typescript：`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+shape | String | rectangle | button shape。options: rectangle/square/round/circle | N
+size | String | medium | a button has four size。options: extra-small/small/medium/large | N
 suffix | Slot / Function | - | Typescript：`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-theme | String | default | button theme。options：default/primary/danger/light | N
-type | String | button | type of button element in html。options：submit/reset/button | N
-variant | String | base | button variant。options：base/outline/text | N
+theme | String | default | button theme。options: default/primary/danger/light | N
+type | String | button | type of button element in html。options: submit/reset/button | N
+variant | String | base | button variant。options: base/outline/text | N
 onClick | Function |  | Typescript：`(e: MouseEvent) => void`<br/>trigger on click | N
 
 ### Button Events
@@ -26,8 +27,8 @@ name | params | description
 -- | -- | --
 click | `(e: MouseEvent)` | trigger on click
 
+### CSS 变量
 
-### CSS Variables
 The component provides the following CSS variables, which can be used to customize styles.
 Name | Default Value | Description 
 -- | -- | --
@@ -129,4 +130,4 @@ Name | Default Value | Description
 --td-button-small-font-size | @font-size-base | - 
 --td-button-small-height | 32px | - 
 --td-button-small-icon-font-size | 18px | - 
---td-button-small-padding-horizontal | 12px | - 
+--td-button-small-padding-horizontal | 12px | -
\ No newline at end of file
diff --git a/src/button/button.md b/src/button/button.md
index 28081cd9..b2cc02ab 100644
--- a/src/button/button.md
+++ b/src/button/button.md
@@ -1,9 +1,10 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Button Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
 block | Boolean | false | 是否为块级元素 | N
 content | String / Slot / Function | - | 按钮内容。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
@@ -13,7 +14,7 @@ icon | Slot / Function | - | 按钮内部图标，可完全自定义。TS 类型
 loading | Boolean | false | 是否显示为加载状态 | N
 loadingProps | Object | - | 透传加载组件全部属性。TS 类型：`LoadingProps`，[Loading API Documents](./loading?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/button/type.ts) | N
 shape | String | rectangle | 按钮形状，有 4 种：长方形、正方形、圆角长方形、圆形。可选项：rectangle/square/round/circle | N
-size | String | medium | 组件尺寸。可选项：extra-small/small/medium/large。TS 类型：`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+size | String | medium | 组件尺寸。可选项：extra-small/small/medium/large | N
 suffix | Slot / Function | - | 右侧内容，可用于定义右侧图标。TS 类型：`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 theme | String | default | 组件风格，依次为品牌色、危险色。可选项：default/primary/danger/light | N
 type | String | button | 按钮类型。可选项：submit/reset/button | N
@@ -26,8 +27,8 @@ onClick | Function |  | TS 类型：`(e: MouseEvent) => void`<br/>点击时触
 -- | -- | --
 click | `(e: MouseEvent)` | 点击时触发
 
-
 ### CSS 变量
+
 组件提供了下列 CSS 变量，可用于自定义样式。
 名称 | 默认值 | 描述 
 -- | -- | --
@@ -129,4 +130,4 @@ click | `(e: MouseEvent)` | 点击时触发
 --td-button-small-font-size | @font-size-base | - 
 --td-button-small-height | 32px | - 
 --td-button-small-icon-font-size | 18px | - 
---td-button-small-padding-horizontal | 12px | - 
+--td-button-small-padding-horizontal | 12px | -
\ No newline at end of file
diff --git a/src/button/button.tsx b/src/button/button.tsx
new file mode 100644
index 00000000..b101331f
--- /dev/null
+++ b/src/button/button.tsx
@@ -0,0 +1,80 @@
+import { computed, toRefs, defineComponent, getCurrentInstance } from 'vue';
+
+import { space } from 'postcss/lib/list';
+import TLoading from '../loading';
+import { Hover } from '../shared';
+import ButtonProps from './props';
+import config from '../config';
+import { useFormDisabled } from '../form/hooks';
+import { TdButtonProps } from './type';
+import { usePrefixClass } from '../hooks/useClass';
+import { useContent, useTNodeJSX } from '../hooks/tnode';
+
+const { prefix } = config;
+const name = `${prefix}-button`;
+
+export default defineComponent({
+  name,
+  directives: { Hover },
+  props: ButtonProps,
+  setup(props) {
+    const buttonClass = usePrefixClass('button');
+    const renderTNodeJSX = useTNodeJSX();
+    const renderTNodeContent = useContent();
+    const isDisabled = useFormDisabled();
+
+    const buttonClasses = computed(() => [
+      `${buttonClass.value}`,
+      `${buttonClass.value}--size-${props.size}`,
+      `${buttonClass.value}--${props.variant}`,
+      {
+        [`${buttonClass.value}--${props.theme}`]: props.theme,
+        [`${buttonClass.value}--${props.shape}`]: props.shape,
+        [`${buttonClass.value}--ghost`]: props.ghost,
+        [`${buttonClass.value}--block`]: props.block,
+        [`${buttonClass.value}--disabled`]: isDisabled.value,
+        [`${buttonClass.value}--loading`]: props.loading,
+      },
+    ]);
+
+    const handleClick = (e: MouseEvent) => {
+      if (!props.loading && !isDisabled.value) {
+        props.onClick?.(e);
+      } else {
+        e.stopPropagation();
+      }
+    };
+
+    return () => {
+      const suffix = renderTNodeJSX('suffix');
+
+      const readerIcon = () => {
+        if (props.loading) {
+          return <TLoading inherit-color {...(props.loadingProps as TdButtonProps['loadingProps'])} />;
+        }
+
+        return renderTNodeJSX('icon');
+      };
+
+      const readerContent = () => {
+        const content = renderTNodeContent('default', 'content');
+        return <span class={`${buttonClass.value}__content`}>{content}</span>;
+      };
+      return (
+        <button
+          class={buttonClasses.value}
+          role="button"
+          type={props.type}
+          disabled={props.disabled}
+          aria-disabled={props.disabled}
+          onClick={handleClick}
+          v-hover={{ className: `${buttonClass.value}--hover` }}
+        >
+          {readerIcon()}
+          {readerContent()}
+          {suffix}
+        </button>
+      );
+    };
+  },
+});
diff --git a/src/button/button.vue b/src/button/button.vue
deleted file mode 100644
index 8e2a7178..00000000
--- a/src/button/button.vue
+++ /dev/null
@@ -1,77 +0,0 @@
-<template>
-  <button
-    v-hover="{ className: `${name}--hover` }"
-    :class="buttonClass"
-    :disabled="disabled"
-    :type="type"
-    role="button"
-    :aria-disabled="disabled"
-    @click="onClick"
-  >
-    <t-loading v-if="loading" inherit-color v-bind="loadingProps" />
-    <t-node v-else :content="iconContent" />
-    <span :class="`${name}__content`">
-      <t-node :content="buttonContent" />
-    </span>
-    <t-node :content="suffixContent" />
-  </button>
-</template>
-
-<script lang="ts">
-import { computed, toRefs, defineComponent, getCurrentInstance } from 'vue';
-
-import Loading from '../loading';
-import { renderContent, renderTNode, TNode, Hover } from '../shared';
-import ButtonProps from './props';
-import config from '../config';
-import { useFormDisabled } from '../form/hooks';
-
-const { prefix } = config;
-const name = `${prefix}-button`;
-
-export default defineComponent({
-  name,
-  components: { TNode, TLoading: Loading },
-  directives: { Hover },
-  props: ButtonProps,
-  emits: ['click'],
-  setup(props) {
-    const disabled = useFormDisabled();
-    const internalInstance = getCurrentInstance();
-    const buttonClass = computed(() => [
-      `${name}`,
-      `${name}--size-${props.size}`,
-      `${name}--${props.variant}`,
-      {
-        [`${name}--${props.theme}`]: props.theme,
-        [`${name}--${props.shape}`]: props.shape,
-        [`${name}--ghost`]: props.ghost,
-        [`${name}--block`]: props.block,
-        [`${name}--disabled`]: disabled.value,
-        [`${name}--loading`]: props.loading,
-      },
-    ]);
-    const buttonContent = computed(() => renderContent(internalInstance, 'default', 'content'));
-    const iconContent = computed(() => renderTNode(internalInstance, 'icon'));
-    const suffixContent = computed(() => renderTNode(internalInstance, 'suffix'));
-
-    const onClick = (e: Event) => {
-      if (!props.loading && !disabled.value) {
-        props.onClick?.(e);
-      } else {
-        e.stopPropagation();
-      }
-    };
-    return {
-      name,
-      ...toRefs(props),
-      disabled,
-      buttonContent,
-      iconContent,
-      suffixContent,
-      buttonClass,
-      onClick,
-    };
-  },
-});
-</script>
diff --git a/src/button/index.ts b/src/button/index.ts
index 296f52d2..ca13bbbc 100644
--- a/src/button/index.ts
+++ b/src/button/index.ts
@@ -1,4 +1,4 @@
-import Button from './button.vue';
+import Button from './button';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/button/type.ts b/src/button/type.ts
index 6e9edfae..2c5e7339 100644
--- a/src/button/type.ts
+++ b/src/button/type.ts
@@ -5,7 +5,7 @@
  * */
 
 import { LoadingProps } from '../loading';
-import { TNode, SizeEnum } from '../common';
+import { TNode } from '../common';
 
 export interface TdButtonProps {
   /**
@@ -49,7 +49,7 @@ export interface TdButtonProps {
    * 组件尺寸
    * @default medium
    */
-  size?: SizeEnum;
+  size?: 'extra-small' | 'small' | 'medium' | 'large';
   /**
    * 右侧内容，可用于定义右侧图标
    */
diff --git a/src/divider/divider.en-US.md b/src/divider/divider.en-US.md
index d5b366c9..6c8512aa 100644
--- a/src/divider/divider.en-US.md
+++ b/src/divider/divider.en-US.md
@@ -6,14 +6,14 @@
 
 name | type | default | description | required
 -- | -- | -- | -- | --
-align | String | center | options：left/right/center | N
+align | String | center | options: left/right/center | 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
 dashed | Boolean | false | \- | N
 default | String / Slot / Function | - | Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-layout | String | horizontal | options：horizontal/vertical | N
+layout | String | horizontal | options: horizontal/vertical | N
 
+### CSS 变量
 
-### CSS Variables
 The component provides the following CSS variables, which can be used to customize styles.
 Name | Default Value | Description 
 -- | -- | --
@@ -21,4 +21,4 @@ Name | Default Value | Description
 --td-divider-content-color | @font-gray-3 | - 
 --td-divider-content-font-size | 12px | - 
 --td-divider-content-line-height | 20px | - 
---td-divider-content-line-style | solid | - 
+--td-divider-content-line-style | solid | -
\ No newline at end of file
diff --git a/src/divider/divider.md b/src/divider/divider.md
index 3ee073a0..08a16e79 100644
--- a/src/divider/divider.md
+++ b/src/divider/divider.md
@@ -1,9 +1,10 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Divider Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
 align | String | center | 文本位置（仅在水平分割线有效）。可选项：left/right/center | N
 content | String / Slot / Function | - | 子元素。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
@@ -11,8 +12,8 @@ dashed | Boolean | false | 是否虚线（仅在水平分割线有效） | N
 default | String / Slot / Function | - | 子元素，同 content。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 layout | String | horizontal | 分隔线类型有两种：水平和垂直。可选项：horizontal/vertical | N
 
-
 ### CSS 变量
+
 组件提供了下列 CSS 变量，可用于自定义样式。
 名称 | 默认值 | 描述 
 -- | -- | --
@@ -20,4 +21,4 @@ layout | String | horizontal | 分隔线类型有两种：水平和垂直。可
 --td-divider-content-color | @font-gray-3 | - 
 --td-divider-content-font-size | 12px | - 
 --td-divider-content-line-height | 20px | - 
---td-divider-content-line-style | solid | - 
+--td-divider-content-line-style | solid | -
\ No newline at end of file
diff --git a/src/divider/divider.tsx b/src/divider/divider.tsx
new file mode 100644
index 00000000..9d11c2b0
--- /dev/null
+++ b/src/divider/divider.tsx
@@ -0,0 +1,33 @@
+import { defineComponent, computed } from 'vue';
+import config from '../config';
+import DividerProps from './props';
+import { useContent } from '../hooks/tnode';
+import { usePrefixClass } from '../hooks/useClass';
+
+const { prefix } = config;
+const name = `${prefix}-divider`;
+export default defineComponent({
+  name,
+  props: DividerProps,
+  setup(props) {
+    const renderTNodeContent = useContent();
+
+    const dividerClass = usePrefixClass('divider');
+    const dividerClasses = computed(() => [
+      `${dividerClass.value}`,
+      `${dividerClass.value}--${props.layout}`,
+      `${dividerClass.value}--${props.align}`,
+      {
+        [`${dividerClass.value}--dashed`]: props.dashed,
+      },
+    ]);
+    return () => {
+      const content = renderTNodeContent('default', 'content');
+      return (
+        <div class={dividerClasses.value} role="separator">
+          <div class={`${dividerClass.value}__content`}>{content}</div>
+        </div>
+      );
+    };
+  },
+});
diff --git a/src/divider/divider.vue b/src/divider/divider.vue
deleted file mode 100644
index 0124517b..00000000
--- a/src/divider/divider.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-<template>
-  <div :class="rootClass" role="separator">
-    <div :class="`${name}__content`">
-      <t-node :content="dividerContent" />
-    </div>
-  </div>
-</template>
-<script lang="ts">
-import { computed, defineProps, getCurrentInstance } from 'vue';
-import { renderContent, TNode } from '../shared';
-import DividerProps from './props';
-import config from '../config';
-
-const { prefix } = config;
-const name = `${prefix}-divider`;
-
-export default {
-  name,
-};
-</script>
-
-<script lang="ts" setup>
-const props = defineProps(DividerProps);
-const internalInstance = getCurrentInstance();
-const dividerContent = computed(() => renderContent(internalInstance, 'default', 'content'));
-const rootClass = computed(() => [
-  `${name}`,
-  `${name}--${props.layout}`,
-  `${name}--${props.align}`,
-  {
-    [`${name}--dashed`]: props.dashed,
-  },
-]);
-</script>
diff --git a/src/divider/index.ts b/src/divider/index.ts
index a8276cc9..663956c9 100644
--- a/src/divider/index.ts
+++ b/src/divider/index.ts
@@ -1,4 +1,4 @@
-import _Divider from './divider.vue';
+import _Divider from './divider';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/fab/fab.en-US.md b/src/fab/fab.en-US.md
index 1c65d96d..51f1a484 100644
--- a/src/fab/fab.en-US.md
+++ b/src/fab/fab.en-US.md
@@ -6,7 +6,7 @@
 
 name | type | default | description | required
 -- | -- | -- | -- | --
-buttonProps | Object | - | \- | N
+buttonProps | Object | - | Typescript：`ButtonProps`，[Button API Documents](./button?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/fab/type.ts) | N
 icon | Slot / Function | - | Typescript：`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 style | String | right: 16px; bottom: 32px; | \- | N
 text | String | - | \- | N
@@ -18,9 +18,9 @@ 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-fab-shadow | @shadow-2 | - 
+--td-fab-shadow | @shadow-2 | -
\ No newline at end of file
diff --git a/src/fab/fab.md b/src/fab/fab.md
index 1f7b0dfe..f0d6bd07 100644
--- a/src/fab/fab.md
+++ b/src/fab/fab.md
@@ -1,11 +1,12 @@
 :: BASE_DOC ::
 
 ## API
+
 ### Fab Props
 
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
 -- | -- | -- | -- | --
-buttonProps | Object | - | 透传至 Button 组件 | N
+buttonProps | Object | - | 透传至 Button 组件。TS 类型：`ButtonProps`，[Button API Documents](./button?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/fab/type.ts) | N
 icon | Slot / Function | - | 图标。TS 类型：`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
 style | String | right: 16px; bottom: 32px; | 悬浮按钮的样式，常用于调整位置 | N
 text | String | - | 文本内容 | N
@@ -17,9 +18,9 @@ onClick | Function |  | TS 类型：`(context: {e: MouseEvent}) => void`<br/>悬
 -- | -- | --
 click | `(context: {e: MouseEvent})` | 悬浮按钮点击事件
 
-
 ### CSS 变量
+
 组件提供了下列 CSS 变量，可用于自定义样式。
 名称 | 默认值 | 描述 
 -- | -- | --
---td-fab-shadow | @shadow-2 | - 
+--td-fab-shadow | @shadow-2 | -
\ No newline at end of file
diff --git a/src/fab/fab.tsx b/src/fab/fab.tsx
new file mode 100644
index 00000000..c79adc13
--- /dev/null
+++ b/src/fab/fab.tsx
@@ -0,0 +1,41 @@
+import { defineComponent } from 'vue';
+import config from '../config';
+import FabProps from './props';
+import { useTNodeJSX } from '../hooks/tnode';
+import { usePrefixClass } from '../hooks/useClass';
+import TButton from '../button';
+import { TdFabProps } from './type';
+
+const { prefix } = config;
+const name = `${prefix}-fab`;
+export default defineComponent({
+  name,
+  props: FabProps,
+  setup(props) {
+    const renderTNodeJSX = useTNodeJSX();
+
+    const fabClass = usePrefixClass('fab');
+
+    const handleClick = (e: MouseEvent) => {
+      props.onClick?.({ e });
+    };
+
+    return () => {
+      const icon = renderTNodeJSX('icon');
+      return (
+        <div class={fabClass.value} style={props.style} onClick={handleClick}>
+          <TButton
+            size="large"
+            theme="primary"
+            shape={props.text ? 'round' : 'circle'}
+            class={`${fabClass.value}__button`}
+            {...(props.buttonProps as TdFabProps['buttonProps'])}
+            icon={icon}
+          >
+            {props.text}
+          </TButton>
+        </div>
+      );
+    };
+  },
+});
diff --git a/src/fab/fab.vue b/src/fab/fab.vue
deleted file mode 100644
index 66df0f34..00000000
--- a/src/fab/fab.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<template>
-  <div :class="classes" :style="style" @click="onClick">
-    <t-button
-      size="large"
-      theme="primary"
-      :shape="props.text ? 'round' : 'circle'"
-      :class="[`${name}__button`]"
-      v-bind="buttonProps"
-      :icon="() => iconTNode"
-    >
-      {{ text }}
-    </t-button>
-  </div>
-</template>
-
-<script lang="ts">
-import { computed, defineProps, defineEmits, getCurrentInstance } from 'vue';
-
-import { renderTNode } from '../shared';
-import fabProps from './props';
-import config from '../config';
-import TButton from '../button';
-
-const { prefix } = config;
-const name = `${prefix}-fab`;
-
-export default {
-  name,
-};
-</script>
-
-<script lang="ts" setup>
-const props = defineProps(fabProps);
-const emit = defineEmits(['click']);
-
-const internalInstance = getCurrentInstance();
-const iconTNode = computed(() => renderTNode(internalInstance, 'icon'));
-
-const classes = computed(() => ({
-  [`${name}`]: true,
-}));
-
-const onClick = (e: MouseEvent) => props.onClick?.({ e });
-</script>
diff --git a/src/fab/index.ts b/src/fab/index.ts
index 36a94c1c..a7ab429d 100644
--- a/src/fab/index.ts
+++ b/src/fab/index.ts
@@ -1,4 +1,4 @@
-import Fab from './fab.vue';
+import Fab from './fab';
 import { withInstall, WithInstallType } from '../shared';
 
 import './style';
diff --git a/src/fab/type.ts b/src/fab/type.ts
index 17971c53..9fc5565d 100644
--- a/src/fab/type.ts
+++ b/src/fab/type.ts
@@ -3,6 +3,7 @@
 /**
  * 该文件为脚本自动生成文件，请勿随意修改。如需修改请联系 PMC
  * */
+
 import { ButtonProps } from '../button';
 import { TNode } from '../common';
 


Test patch:
diff --git a/src/badge/__test__/index.test.jsx b/src/badge/__test__/index.test.jsx
index b92c2538..ccddbc44 100644
--- a/src/badge/__test__/index.test.jsx
+++ b/src/badge/__test__/index.test.jsx
@@ -1,7 +1,7 @@
 import { mount } from '@vue/test-utils';
 import { describe, it, expect } from 'vitest';
 import Badge from '../badge.vue';
-import Button from '../../button/button.vue';
+import Button from '../../button/button';
 import config from '../../config';
 
 const { prefix } = config;
diff --git a/src/button/__test__/index.test.jsx b/src/button/__test__/index.test.jsx
index eff53606..736a54ea 100644
--- a/src/button/__test__/index.test.jsx
+++ b/src/button/__test__/index.test.jsx
@@ -2,7 +2,7 @@ import { h } from 'vue';
 import { mount } from '@vue/test-utils';
 import { describe, it, expect, vi } from 'vitest';
 import { AppIcon as TIconApp } from 'tdesign-icons-vue-next';
-import Button from '../button.vue';
+import Button from '../button';
 import Loading from '../../loading';
 
 const prefix = 't';
diff --git a/src/dialog/__test__/index.test.jsx b/src/dialog/__test__/index.test.jsx
index be5ce079..862aba72 100644
--- a/src/dialog/__test__/index.test.jsx
+++ b/src/dialog/__test__/index.test.jsx
@@ -1,7 +1,7 @@
 import { config, mount } from '@vue/test-utils';
 import { describe, it, expect, vi } from 'vitest';
 import Dialog from '../dialog.vue';
-import Button from '../../button/button.vue';
+import Button from '../../button/button';
 import { CloseIcon } from 'tdesign-icons-vue-next';
 
 import prefixConfig from '../../config';
diff --git a/src/divider/__test__/index.test.jsx b/src/divider/__test__/index.test.jsx
index 722a03a1..b3bf500d 100644
--- a/src/divider/__test__/index.test.jsx
+++ b/src/divider/__test__/index.test.jsx
@@ -1,6 +1,6 @@
 import { mount } from '@vue/test-utils';
 import { describe, it, expect } from 'vitest';
-import Divider from '../divider.vue';
+import Divider from '../divider';
 import config from '../../config';
 
 const { prefix } = config;
diff --git a/src/fab/__test__/index.test.jsx b/src/fab/__test__/index.test.jsx
index 4807e9ab..d635384e 100644
--- a/src/fab/__test__/index.test.jsx
+++ b/src/fab/__test__/index.test.jsx
@@ -1,6 +1,6 @@
 import { mount } from '@vue/test-utils';
 import { describe, it, expect, vi } from 'vitest';
-import Fab from '../fab.vue';
+import Fab from '../fab';
 import { AppIcon as TIconApp, MoreIcon } from 'tdesign-icons-vue-next';
 
 describe('fab', () => {