Repository: Tencent/tdesign-mobile-vue
Pull request #898 (2023-06-25 09:01:20)

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


github-actions[bot]: [<img height="96" alt="失败" src="https://user-images.githubusercontent.com/5378891/75333447-1e63a280-58c1-11ea-975d-235367fd1522.png">](https://github.com/Tencent/tdesign-mobile-vue/actions/runs/5368940741)
<!-- AUTO_PREVIEW_HOOK -->
github-actions[bot]: **Size Change:** +24.5 kB (+5%) 🔍

**Total Size:** 497 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `./dist/tdesign.css` | 37.3 kB | +897 B (+2%) |  |
| `./dist/tdesign.js` | 292 kB | +15.3 kB (+6%) | 🔍 |
| `./dist/tdesign.min.css` | 27.1 kB | +731 B (+3%) |  |
| `./dist/tdesign.min.js` | 141 kB | +7.6 kB (+6%) | 🔍 |

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

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |

</details>


github-actions[bot]: **Size Change:** +24.7 kB (+5%) 🔍

**Total Size:** 497 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `./dist/tdesign.css` | 37.4 kB | +979 B (+3%) |  |
| `./dist/tdesign.js` | 292 kB | +15.3 kB (+6%) | 🔍 |
| `./dist/tdesign.min.css` | 27.1 kB | +807 B (+3%) |  |
| `./dist/tdesign.min.js` | 141 kB | +7.6 kB (+6%) | 🔍 |

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

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |

</details>


github-actions[bot]: **Size Change:** +24.7 kB (+5%) 🔍

**Total Size:** 498 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `./dist/tdesign.css` | 37.4 kB | +980 B (+3%) |  |
| `./dist/tdesign.js` | 292 kB | +15.3 kB (+6%) | 🔍 |
| `./dist/tdesign.min.css` | 27.1 kB | +808 B (+3%) |  |
| `./dist/tdesign.min.js` | 141 kB | +7.6 kB (+6%) | 🔍 |

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

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |

</details>


github-actions[bot]: **Size Change:** +24.7 kB (+5%) 🔍

**Total Size:** 498 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `./dist/tdesign.css` | 37.4 kB | +980 B (+3%) |  |
| `./dist/tdesign.js` | 292 kB | +15.3 kB (+6%) | 🔍 |
| `./dist/tdesign.min.css` | 27.1 kB | +808 B (+3%) |  |
| `./dist/tdesign.min.js` | 141 kB | +7.6 kB (+6%) | 🔍 |

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

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |

</details>


github-actions[bot]: **Size Change:** +24.7 kB (+5%) 🔍

**Total Size:** 498 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `./dist/tdesign.css` | 37.4 kB | +980 B (+3%) |  |
| `./dist/tdesign.js` | 292 kB | +15.3 kB (+6%) | 🔍 |
| `./dist/tdesign.min.css` | 27.1 kB | +808 B (+3%) |  |
| `./dist/tdesign.min.js` | 141 kB | +7.6 kB (+6%) | 🔍 |

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

| Filename | Size |
| :--- | :---: |
| `./dist/reset.css` | 672 B |

</details>



Patch:
diff --git a/package.json b/package.json
index 1ab98a2d..820ca859 100644
--- a/package.json
+++ b/package.json
@@ -101,7 +101,7 @@
     "@babel/runtime": "^7.16.5",
     "@commitlint/cli": "^12.0.1",
     "@commitlint/config-conventional": "^12.0.1",
-    "@popperjs/core": "^2.6.0",
+    "@popperjs/core": "^2.11.8",
     "@rollup/plugin-babel": "^5.2.2",
     "@rollup/plugin-commonjs": "^21.0.1",
     "@rollup/plugin-eslint": "^8.0.1",
diff --git a/site/docs.config.js b/site/docs.config.js
index 2ce45bce..d706374e 100644
--- a/site/docs.config.js
+++ b/site/docs.config.js
@@ -366,6 +366,12 @@ export default {
           path: '/mobile-vue/components/dialog',
           component: () => import('@/dialog/dialog.md'),
         },
+        {
+          title: 'Popover 弹出气泡',
+          name: 'popover',
+          path: '/mobile-vue/components/popover',
+          component: () => import('@/popover/popover.md'),
+        },
         {
           title: 'Popup 弹出层',
           name: 'popup',
diff --git a/src/_common b/src/_common
index 00688b90..c4dc2ec8 160000
--- a/src/_common
+++ b/src/_common
@@ -1,1 +1,1 @@
-Subproject commit 00688b90a423cefc41237351456586189d3c3969
+Subproject commit c4dc2ec832a3df597a436e18fcfb0d2cd7149925
diff --git a/src/components.ts b/src/components.ts
index b14fb4f8..10aae22f 100644
--- a/src/components.ts
+++ b/src/components.ts
@@ -55,3 +55,4 @@ export { Form, FormItem } from './form';
 export { default as Icon } from './icon';
 export { default as Table } from './table';
 export { SideBar, SideBarItem } from './side-bar';
+export { default as TPopover } from './popover';
diff --git a/src/link/link.vue b/src/link/link.vue
index f527949f..be8ce71b 100644
--- a/src/link/link.vue
+++ b/src/link/link.vue
@@ -6,13 +6,13 @@
     :aria-disabled="disabled"
     @click="handleClick"
   >
-    <span v-if="prefixContent" :class="`${baseClass}__prefix-icon ${prefix}-class-prefix-icon`">
+    <span v-if="prefixContent" :class="`${name}__prefix-icon ${prefix}-class-prefix-icon`">
       <t-node :content="prefixContent"></t-node>
     </span>
-    <span :class="`${baseClass}__content`">
+    <span :class="`${name}__content`">
       <t-node :content="linkContent"></t-node>
     </span>
-    <span v-if="suffixContent" :class="`${baseClass}__suffix-icon ${prefix}-class-suffix-icon`">
+    <span v-if="suffixContent" :class="`${name}__suffix-icon ${prefix}-class-suffix-icon`">
       <t-node :content="suffixContent"></t-node>
     </span>
   </a>
@@ -34,7 +34,6 @@ export default defineComponent({
   },
   props: LinkProps,
   setup(props, context) {
-    const baseClass = name;
     const emitEvent = useEmitEvent(props, context.emit);
     const _this = getCurrentInstance();
     const linkContent = computed(() => renderContent(_this, 'default', 'content'));
@@ -46,21 +45,21 @@ export default defineComponent({
       emitEvent('click', e);
     };
 
-    const linkClass = [
-      baseClass,
-      `${baseClass}--${props.theme}`,
-      `${name}--${props.size}`,
+    const linkClass = computed(() => [
+      name,
+      `${name}--${props.theme || 'default'}`,
+      `${name}--${props.size || 'medium'}`,
       {
         [`${name}--disabled`]: props.disabled,
         [`${name}--underline`]: props.underline,
         [`${name}--hover`]: props.hover && !props.disabled,
       },
-    ];
+    ]);
 
     return {
       prefix,
       linkClass,
-      baseClass,
+      name,
       handleClick,
       linkContent,
       prefixContent,
diff --git a/src/popover/demos/mobile.vue b/src/popover/demos/mobile.vue
new file mode 100644
index 00000000..8eabbf0b
--- /dev/null
+++ b/src/popover/demos/mobile.vue
@@ -0,0 +1,26 @@
+<template>
+  <div class="tdesign-mobile-demo">
+    <h1 class="title">Popover 弹出气泡</h1>
+    <p class="summary">用于文字提示的气泡框。</p>
+    <tdesign-demo-block title="01 组件类型">
+      <typeDemo />
+    </tdesign-demo-block>
+    <tdesign-demo-block title="02 组件样式">
+      <themeDemo />
+    </tdesign-demo-block>
+    <tdesign-demo-block>
+      <placementDemo />
+    </tdesign-demo-block>
+  </div>
+</template>
+<script lang="ts" setup>
+import typeDemo from './type.vue';
+import themeDemo from './theme.vue';
+import placementDemo from './placement.vue';
+</script>
+
+<style lang="less" scoped>
+.tdesign-mobile-demo {
+  background-color: #fff;
+}
+</style>
diff --git a/src/popover/demos/placement.vue b/src/popover/demos/placement.vue
new file mode 100644
index 00000000..27314853
--- /dev/null
+++ b/src/popover/demos/placement.vue
@@ -0,0 +1,250 @@
+<template>
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">顶部弹出气泡</div>
+    <div class="popover-example__content row mb-24">
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[0]" placement="top-left" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(0)"
+            >
+              顶部左
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[1]" placement="top" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(1)"
+            >
+              顶部中
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[2]" placement="top-right" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(2)"
+            >
+              顶部右
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+    </div>
+  </div>
+
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">底部弹出气泡</div>
+    <div class="popover-example__content row mb-24">
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[3]" placement="bottom-left" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(3)"
+            >
+              底部左
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[4]" placement="bottom" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(4)"
+            >
+              底部中
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[5]" placement="bottom-right" theme="dark" content="弹出气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-width--small"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(5)"
+            >
+              底部右
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+    </div>
+  </div>
+
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">右侧弹出气泡</div>
+    <div class="popover-example__content column mb-24">
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[6]" placement="right-top" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button class="button-with--large" theme="primary" variant="outline" size="large" @click="handleClick(6)">
+              右侧上
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[7]" placement="right" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button class="button-with--large" theme="primary" variant="outline" size="large" @click="handleClick(7)">
+              右侧中
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[8]" placement="right-bottom" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button class="button-with--large" theme="primary" variant="outline" size="large" @click="handleClick(8)">
+              右侧下
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+    </div>
+  </div>
+
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">左侧弹出气泡</div>
+    <div class="popover-example__content column flex-end mb-24">
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[9]" placement="left-top" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button class="button-with--large" theme="primary" variant="outline" size="large" @click="handleClick(9)">
+              左侧上
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[10]" placement="left" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-with--large"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(10)"
+            >
+              左侧中
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+      <div class="popover-example__content__item">
+        <t-popover :visible="visibleList[11]" placement="left-bottom" theme="dark" content="气泡内容">
+          <template #triggerElement>
+            <t-button
+              class="button-with--large"
+              theme="primary"
+              variant="outline"
+              size="large"
+              @click="handleClick(11)"
+            >
+              左侧下
+            </t-button>
+          </template>
+        </t-popover>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const visibleList = ref([false, false, false, false, false, false, false, false, false, false, false, false]);
+
+const handleClick = (number: number) => {
+  const newVisibleList = visibleList.value.map((item, index) => {
+    if (index === number) {
+      return !item;
+    }
+    return false;
+  });
+  visibleList.value = newVisibleList;
+};
+</script>
+
+<style lang="less" scoped>
+.popover-example {
+  padding: 0 16px;
+
+  &__summary {
+    font-size: 14px;
+    color: rgba(0, 0, 0, 0.6);
+    line-height: 22px;
+  }
+
+  &__content {
+    display: flex;
+
+    &__item {
+      flex: 1;
+    }
+  }
+
+  .row {
+    .popover-example__content__item:not(:last-child) {
+      margin-right: 16px;
+    }
+  }
+
+  .column {
+    flex-direction: column;
+
+    .popover-example__content__item:not(:last-child) {
+      margin-bottom: 16px;
+    }
+  }
+
+  .flex-end {
+    align-items: flex-end;
+  }
+}
+
+.button-width--small {
+  width: 102px;
+}
+
+.button-with--large {
+  width: 223px;
+}
+
+.mb-24 {
+  margin-bottom: 24px;
+}
+
+.mb-16 {
+  margin-bottom: 16px;
+}
+</style>
diff --git a/src/popover/demos/theme.vue b/src/popover/demos/theme.vue
new file mode 100644
index 00000000..b1ec48f8
--- /dev/null
+++ b/src/popover/demos/theme.vue
@@ -0,0 +1,106 @@
+<template>
+  <div class="popover-example">
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[0]" placement="top" theme="dark" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(0)">
+            深色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[1]" placement="top" theme="light" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(1)">
+            浅色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[2]" placement="top" theme="brand" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(2)">
+            品牌色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+  </div>
+  <div class="popover-example">
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[3]" placement="top" theme="success" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(3)">
+            成功色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[4]" placement="top" theme="warning" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(4)">
+            警告色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+    <div class="popover-example__content">
+      <t-popover :visible="visibleList[5]" placement="top" theme="error" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button class="button-width--small" theme="primary" variant="outline" size="large" @click="handleClick(5)">
+            错误色
+          </t-button>
+        </template>
+      </t-popover>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const visibleList = ref([false, false, false, false, false, false]);
+
+const handleClick = (number: number) => {
+  const newVisibleList = visibleList.value.map((item, index) => {
+    if (index === number) {
+      return !item;
+    }
+    return false;
+  });
+  visibleList.value = newVisibleList;
+};
+</script>
+
+<style lang="less" scoped>
+.popover-example {
+  display: flex;
+  padding: 0 16px;
+
+  &:not(:last-child) {
+    margin-bottom: 16px;
+  }
+
+  &__content {
+    flex: 1;
+
+    &:not(:last-child) {
+      margin-right: 16px;
+    }
+  }
+}
+
+.button-width--small {
+  width: 102px;
+}
+
+.mb-24 {
+  margin-bottom: 24px;
+}
+
+.mb-16 {
+  margin-bottom: 16px;
+}
+</style>
diff --git a/src/popover/demos/type.vue b/src/popover/demos/type.vue
new file mode 100644
index 00000000..5381774a
--- /dev/null
+++ b/src/popover/demos/type.vue
@@ -0,0 +1,107 @@
+<template>
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">带箭头的弹出气泡</div>
+    <div class="popover-example__content mb-24">
+      <t-popover
+        :visible="visibleList[0]"
+        placement="top"
+        theme="dark"
+        content="弹出气泡内容"
+        @visible-change="handleVisibleChange"
+      >
+        <template #triggerElement>
+          <t-button theme="primary" variant="outline" size="large" @click="handleClick(0)">带箭头</t-button>
+        </template>
+      </t-popover>
+    </div>
+  </div>
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">不带箭头的弹出气泡</div>
+    <div class="popover-example__content mb-24">
+      <t-popover :visible="visibleList[1]" placement="top" theme="dark" :show-arrow="false" content="弹出气泡内容">
+        <template #triggerElement>
+          <t-button theme="primary" variant="outline" size="large" @click="handleClick(1)">不带箭头</t-button>
+        </template>
+      </t-popover>
+    </div>
+  </div>
+  <div class="popover-example">
+    <div class="popover-example__summary mb-16">自定义内容弹出气泡</div>
+    <div class="custom popover-example__content mb-24">
+      <t-popover :visible="visibleList[2]" placement="top" theme="dark">
+        <template #triggerElement>
+          <t-button theme="primary" variant="outline" size="large" @click="handleClick(2)">自定义内容</t-button>
+        </template>
+        <template #content>
+          <div class="custom__list">
+            <div v-for="i in 3" :key="i" class="custom__item">选项{{ i }}</div>
+          </div>
+        </template>
+      </t-popover>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const visibleList = ref([false, false, false]);
+
+const handleClick = (number: number) => {
+  const newVisibleList = visibleList.value.map((item, index) => {
+    if (index === number) {
+      return !item;
+    }
+    return false;
+  });
+  visibleList.value = newVisibleList;
+};
+
+const handleVisibleChange = (visible: boolean) => {
+  console.log('visible is: ', visible);
+};
+</script>
+
+<style lang="less" scoped>
+.popover-example {
+  padding: 0 16px;
+
+  &__content {
+    display: flex;
+    justify-content: center;
+  }
+
+  &__summary {
+    font-size: 14px;
+    color: rgba(0, 0, 0, 0.6);
+    line-height: 22px;
+  }
+}
+
+.custom {
+  --td-popover-padding: 0;
+}
+.custom__list {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  color: #fff;
+}
+
+.custom__item {
+  width: 105px;
+  line-height: 24px;
+  text-align: center;
+  padding: 12px;
+
+  &:not(:last-child) {
+    border-bottom: 1px solid #fff;
+  }
+}
+.mb-24 {
+  margin-bottom: 24px;
+}
+
+.mb-16 {
+  margin-bottom: 16px;
+}
+</style>
diff --git a/src/popover/index.ts b/src/popover/index.ts
new file mode 100644
index 00000000..3e97de60
--- /dev/null
+++ b/src/popover/index.ts
@@ -0,0 +1,11 @@
+import Popover from './popover.vue';
+import { withInstall, WithInstallType } from '../shared';
+import { TdPopoverProps } from './type';
+
+import './style';
+
+export * from './type';
+export type PopoverProps = TdPopoverProps;
+
+const _Popover: WithInstallType<typeof Popover> = withInstall(Popover);
+export default _Popover;
diff --git a/src/popover/popover.en-US.md b/src/popover/popover.en-US.md
new file mode 100644
index 00000000..7f1646f5
--- /dev/null
+++ b/src/popover/popover.en-US.md
@@ -0,0 +1,21 @@
+:: BASE_DOC ::
+
+## API
+### Popover Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+content | String / Slot / Function | - | Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | 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
+placement | String | top | options：top/left/right/bottom/top-left/top-right/bottom-left/bottom-right/left-top/left-bottom/right-top/right-bottom | N
+showArrow | Boolean | true | \- | N
+theme | String | dark | options：dark/light/brand/success/warning/error | N
+triggerElement | String / Slot / Function | - | Typescript：`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+visible | Boolean | - | `v-model` and `v-model:visible` is supported | N
+onVisibleChange | Function |  | Typescript：`(visible: boolean) => void`<br/> | N
+
+### Popover Events
+
+name | params | description
+-- | -- | --
+visible-change | `(visible: boolean)` | \-
diff --git a/src/popover/popover.md b/src/popover/popover.md
new file mode 100644
index 00000000..c0a95091
--- /dev/null
+++ b/src/popover/popover.md
@@ -0,0 +1,21 @@
+:: BASE_DOC ::
+
+## API
+### Popover Props
+
+名称 | 类型 | 默认值 | 说明 | 必传
+-- | -- | -- | -- | --
+content | String / Slot / Function | - | 确认框内容。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+default | String / Slot / Function | - | 触发元素，同 triggerElement。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+placement | String | top | 浮层出现位置。可选项：top/left/right/bottom/top-left/top-right/bottom-left/bottom-right/left-top/left-bottom/right-top/right-bottom | N
+showArrow | Boolean | true | 是否显示浮层箭头 | N
+theme | String | dark | 弹出气泡主题。。可选项：dark/light/brand/success/warning/error | N
+triggerElement | String / Slot / Function | - | 触发元素。TS 类型：`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+visible | Boolean | - | 是否显示气泡确认框。支持语法糖 `v-model` 或 `v-model:visible` | N
+onVisibleChange | Function |  | TS 类型：`(visible: boolean) => void`<br/>确认框显示或隐藏时触发 | N
+
+### Popover Events
+
+名称 | 参数 | 描述
+-- | -- | --
+visible-change | `(visible: boolean)` | 确认框显示或隐藏时触发
diff --git a/src/popover/popover.vue b/src/popover/popover.vue
new file mode 100644
index 00000000..33c95415
--- /dev/null
+++ b/src/popover/popover.vue
@@ -0,0 +1,101 @@
+<template>
+  <div ref="referenceRef" :class="`${name}__wrapper`">
+    <t-node :content="triggerElementContent"></t-node>
+  </div>
+
+  <Transition :name="`${name}--animation`" appear @enter="updatePopper" @after-leave="destroyPopper">
+    <div v-show="currentVisible" ref="popoverRef" data-popper-placement :class="[`${name}`]">
+      <div :class="contentClasses">
+        <t-node :content="content"></t-node>
+        <div v-if="showArrow" :class="`${name}__arrow`" />
+      </div>
+    </div>
+  </Transition>
+</template>
+<script lang="ts">
+import { defineComponent, getCurrentInstance, computed, ref, toRefs, provide, watch } from 'vue';
+import { createPopper, Placement } from '@popperjs/core';
+import PopoverProps from './props';
+import { TdPopoverProps } from './type';
+import config from '../config';
+import { renderContent, renderTNode, TNode, useDefault } from '../shared';
+
+const { prefix } = config;
+const name = `${prefix}-popover`;
+
+export default defineComponent({
+  name,
+  components: { TNode },
+  props: PopoverProps,
+  emits: ['visible-change', 'update:visible', 'update:modelValue'],
+  setup(props, context) {
+    const [currentVisible, setVisible] = useDefault<TdPopoverProps['visible'], TdPopoverProps>(
+      props,
+      context.emit,
+      'visible',
+      'visible-change',
+    );
+
+    const internalInstance = getCurrentInstance();
+    const referenceRef = ref<HTMLElement>();
+    const popoverRef = ref<HTMLElement>();
+
+    const contentClasses = computed(() => [`${name}__content`, `${name}--${props.theme}`]);
+
+    /** popperjs instance */
+    let popper: ReturnType<typeof createPopper>;
+    const content = computed(() => renderTNode(internalInstance, 'content'));
+    const triggerElementContent = computed(() => renderContent(internalInstance, 'default', 'triggerElement'));
+
+    const getPopperPlacement = (placement: TdPopoverProps['placement']): Placement => {
+      return placement?.replace(/-(left|top)$/, '-start').replace(/-(right|bottom)$/, '-end') as Placement;
+    };
+
+    const getPopoverOptions = () => ({
+      placement: getPopperPlacement(props.placement),
+    });
+
+    const updatePopper = () => {
+      if (referenceRef.value && popoverRef.value) {
+        popper = createPopper(referenceRef.value, popoverRef.value, getPopoverOptions());
+      }
+      return null;
+    };
+
+    const destroyPopper = () => {
+      if (popper) {
+        popper?.destroy();
+        // @ts-ignore
+        popper = null;
+      }
+    };
+
+    watch(
+      () => currentVisible.value,
+      (val) => {
+        setVisible(val);
+      },
+    );
+
+    watch(
+      () => props.placement,
+      () => {
+        destroyPopper();
+        updatePopper();
+      },
+    );
+
+    return {
+      name,
+      currentVisible,
+      referenceRef,
+      popoverRef,
+      triggerElementContent,
+      content,
+      contentClasses,
+      updatePopper,
+      destroyPopper,
+    };
+  },
+});
+</script>
diff --git a/src/popover/props.ts b/src/popover/props.ts
new file mode 100644
index 00000000..9b99fef6
--- /dev/null
+++ b/src/popover/props.ts
@@ -0,0 +1,72 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件，请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TdPopoverProps } from './type';
+import { PropType } from 'vue';
+
+export default {
+  /** 确认框内容 */
+  content: {
+    type: [String, Function] as PropType<TdPopoverProps['content']>,
+  },
+  /** 触发元素，同 triggerElement */
+  default: {
+    type: [String, Function] as PropType<TdPopoverProps['default']>,
+  },
+  /** 浮层出现位置 */
+  placement: {
+    type: String as PropType<TdPopoverProps['placement']>,
+    default: 'top' as TdPopoverProps['placement'],
+    validator(val: TdPopoverProps['placement']): boolean {
+      if (!val) return true;
+      return [
+        'top',
+        'left',
+        'right',
+        'bottom',
+        'top-left',
+        'top-right',
+        'bottom-left',
+        'bottom-right',
+        'left-top',
+        'left-bottom',
+        'right-top',
+        'right-bottom',
+      ].includes(val);
+    },
+  },
+  /** 是否显示浮层箭头 */
+  showArrow: {
+    type: Boolean,
+    default: true,
+  },
+  /** 弹出气泡主题。 */
+  theme: {
+    type: String as PropType<TdPopoverProps['theme']>,
+    default: 'dark' as TdPopoverProps['theme'],
+    validator(val: TdPopoverProps['theme']): boolean {
+      if (!val) return true;
+      return ['dark', 'light', 'brand', 'success', 'warning', 'error'].includes(val);
+    },
+  },
+  /** 触发元素 */
+  triggerElement: {
+    type: [String, Function] as PropType<TdPopoverProps['triggerElement']>,
+  },
+  /** 是否显示气泡确认框 */
+  visible: {
+    type: Boolean,
+    default: undefined,
+  },
+  modelValue: {
+    type: Boolean,
+    default: undefined,
+  },
+  /** 是否显示气泡确认框，非受控属性 */
+  defaultVisible: Boolean,
+  /** 确认框显示或隐藏时触发 */
+  onVisibleChange: Function as PropType<TdPopoverProps['onVisibleChange']>,
+};
diff --git a/src/popover/style/css.js b/src/popover/style/css.js
new file mode 100644
index 00000000..6a9a4b13
--- /dev/null
+++ b/src/popover/style/css.js
@@ -0,0 +1,1 @@
+import './index.css';
diff --git a/src/popover/style/index.js b/src/popover/style/index.js
new file mode 100644
index 00000000..43c5780a
--- /dev/null
+++ b/src/popover/style/index.js
@@ -0,0 +1,1 @@
+import '../../_common/style/mobile/components/popover/_index.less';
diff --git a/src/popover/type.ts b/src/popover/type.ts
new file mode 100644
index 00000000..9769a8aa
--- /dev/null
+++ b/src/popover/type.ts
@@ -0,0 +1,65 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件，请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TNode } from '../common';
+
+export interface TdPopoverProps {
+  /**
+   * 确认框内容
+   */
+  content?: string | TNode;
+  /**
+   * 触发元素，同 triggerElement
+   */
+  default?: string | TNode;
+  /**
+   * 浮层出现位置
+   * @default top
+   */
+  placement?:
+    | 'top'
+    | 'left'
+    | 'right'
+    | 'bottom'
+    | 'top-left'
+    | 'top-right'
+    | 'bottom-left'
+    | 'bottom-right'
+    | 'left-top'
+    | 'left-bottom'
+    | 'right-top'
+    | 'right-bottom';
+  /**
+   * 是否显示浮层箭头
+   * @default true
+   */
+  showArrow?: boolean;
+  /**
+   * 弹出气泡主题。
+   * @default dark
+   */
+  theme?: 'dark' | 'light' | 'brand' | 'success' | 'warning' | 'error';
+  /**
+   * 触发元素
+   */
+  triggerElement?: string | TNode;
+  /**
+   * 是否显示气泡确认框
+   */
+  visible?: boolean;
+  /**
+   * 是否显示气泡确认框，非受控属性
+   */
+  defaultVisible?: boolean;
+  /**
+   * 是否显示气泡确认框
+   */
+  modelValue?: boolean;
+  /**
+   * 确认框显示或隐藏时触发
+   */
+  onVisibleChange?: (visible: boolean) => void;
+}
diff --git a/src/popup/props.ts b/src/popup/props.ts
index 5a1ff0cb..41b757ec 100644
--- a/src/popup/props.ts
+++ b/src/popup/props.ts
@@ -32,7 +32,7 @@ export default {
   /** 浮层出现位置 */
   placement: {
     type: String as PropType<TdPopupProps['placement']>,
-    default: 'top' as TdPopupProps['placement'],
+    // default: 'top' as TdPopupProps['placement'],
     validator(val: TdPopupProps['placement']): boolean {
       if (!val) return true;
       return ['top', 'left', 'right', 'bottom', 'center'].includes(val);
diff --git a/src/popup/type.ts b/src/popup/type.ts
index b6dab241..9ff0e0cb 100644
--- a/src/popup/type.ts
+++ b/src/popup/type.ts
@@ -35,7 +35,7 @@ export interface TdPopupProps {
    * 浮层出现位置
    * @default top
    */
-  placement?: 'top' | 'left' | 'right' | 'bottom' | 'center';
+  placement?: 'top' | 'left' | 'right' | 'bottom' | 'center' | '';
   /**
    * 防止滚动穿透
    * @default true
diff --git a/src/result/result.vue b/src/result/result.vue
index ac41274c..c5864864 100644
--- a/src/result/result.vue
+++ b/src/result/result.vue
@@ -46,7 +46,7 @@ export default defineComponent({
     const titleContent = computed(() => renderTNode(internalInstance, 'title'));
     const descriptionContent = computed(() => renderTNode(internalInstance, 'description'));
 
-    const classes = computed(() => [`${name}`, `${name}--theme-${props.theme}`]);
+    const classes = computed(() => [`${name}`, `${name}--theme-${props.theme || 'default'}`]);
 
     let iconContent: any;
     if (props?.theme) {
diff --git a/src/textarea/demos/maxcharacter.vue b/src/textarea/demos/maxcharacter.vue
index 94491045..d0d49c48 100644
--- a/src/textarea/demos/maxcharacter.vue
+++ b/src/textarea/demos/maxcharacter.vue
@@ -1,11 +1,8 @@
 <template>
-  <t-textarea
-    name="标签文字"
-    label="标签文字"
-    placeholder="请输入文字"
-    :maxcharacter="500"
-    indicator
-    :allow-input-over-max="true"
-  />
+  <t-textarea v-model="value" name="标签文字" label="标签文字" placeholder="请输入文字" :maxcharacter="500" indicator />
 </template>
-<script lang="ts" setup></script>
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const value = ref('');
+</script>
diff --git a/src/textarea/demos/maxlength.vue b/src/textarea/demos/maxlength.vue
index 94ec5f0c..7b610c57 100644
--- a/src/textarea/demos/maxlength.vue
+++ b/src/textarea/demos/maxlength.vue
@@ -1,11 +1,8 @@
 <template>
-  <t-textarea
-    name="标签文字"
-    label="标签文字"
-    placeholder="请输入文字"
-    :maxlength="500"
-    indicator
-    :allow-input-over-max="true"
-  />
+  <t-textarea v-model="value" name="标签文字" label="标签文字" placeholder="请输入文字" :maxlength="500" indicator />
 </template>
-<script lang="ts" setup></script>
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const value = ref('');
+</script>
diff --git a/src/textarea/textarea.vue b/src/textarea/textarea.vue
index 044205d2..07ada656 100644
--- a/src/textarea/textarea.vue
+++ b/src/textarea/textarea.vue
@@ -94,34 +94,33 @@ export default defineComponent({
 
     const handleInput = (e: any) => {
       if (e.isComposing || e.inputType === 'insertCompositionText') return;
-      textareaValueChangeHandle(e);
+      textareaValueChangeHandle();
     };
 
-    const textareaValueChangeHandle = (e: InputEvent) => {
-      const { target } = e;
-      const { value } = target as HTMLInputElement;
+    const textareaValueChangeHandle = () => {
+      const textarea = textareaRef.value as HTMLInputElement;
       if (
         !props.allowInputOverMax &&
         props.maxcharacter &&
         props.maxcharacter > 0 &&
         !Number.isNaN(props.maxcharacter)
       ) {
-        const { length = 0, characters = '' } = getCharacterLength(value, props.maxcharacter) as {
+        const { length = 0, characters = '' } = getCharacterLength(textarea.value, props.maxcharacter) as {
           length: number;
           characters: string;
         };
         setInnerValue(characters);
         textareaLength.value = length;
       } else {
-        setInnerValue(value);
-        textareaLength.value = String(innerValue.value).length;
+        setInnerValue(textarea.value);
+        textareaLength.value = String(textarea.value).length;
       }
       nextTick(() => setInputValue(innerValue.value));
       adjustTextareaHeight();
     };
 
     const handleCompositionend = (e: InputEvent | CompositionEvent) => {
-      textareaValueChangeHandle(e as InputEvent);
+      textareaValueChangeHandle();
     };
 
     const handleFocus = (e: FocusEvent) => {
@@ -135,6 +134,7 @@ export default defineComponent({
       if (props.autofocus) {
         textareaRef.value?.focus();
       }
+      textareaValueChangeHandle();
       adjustTextareaHeight();
     });
 


Test patch:
diff --git a/src/avatar/__test__/index.test.jsx b/src/avatar/__test__/index.test.jsx
index c7a1b57e..a10f4f8e 100644
--- a/src/avatar/__test__/index.test.jsx
+++ b/src/avatar/__test__/index.test.jsx
@@ -110,7 +110,7 @@ describe('avatar-group', async () => {
   it(': cascading', async () => {
     sizeList.forEach((s) => {
       const wrapper = mount(() => (
-        <AvatarGroup cascading="" size={s}>
+        <AvatarGroup cascading={''} size={s}>
           <Avatar image={IMAGE}></Avatar>
           <Avatar image={IMAGE}></Avatar>
         </AvatarGroup>
diff --git a/src/image/__test__/__snapshots__/demo.test.jsx.snap b/src/image/__test__/__snapshots__/demo.test.jsx.snap
index 232c1bb7..c0fa6e88 100644
--- a/src/image/__test__/__snapshots__/demo.test.jsx.snap
+++ b/src/image/__test__/__snapshots__/demo.test.jsx.snap
@@ -1679,6 +1679,591 @@ exports[`Image > Image mobileVue demo works fine 1`] = `
 </div>
 `;
 
+exports[`Image > Image positionVue demo works fine 1`] = `
+<div
+  class="image-example"
+  data-v-2d6651f5=""
+>
+  <div
+    class="image-example-title"
+    data-v-2d6651f5=""
+  >
+    不同填充位置的图片
+  </div>
+  <div
+    class="image-example-desc"
+    data-v-2d6651f5=""
+  >
+    当图片过大时，提供显示图片的局部左侧对齐、或右侧对齐的不同位置。
+  </div>
+  <div
+    class="image-group"
+    data-v-2d6651f5=""
+  >
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        cover center
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 72px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: cover; object-position: center;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        cover left
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 72px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: cover; object-position: left;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        cover right
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 72px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: cover; object-position: right;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        cover top
+      </p>
+      <div
+        class="t-image t-image--square"
+        data-v-2d6651f5=""
+        style="width: 240px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: cover; object-position: top;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        cover bottom
+      </p>
+      <div
+        class="t-image t-image--square"
+        data-v-2d6651f5=""
+        style="width: 240px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: cover; object-position: bottom;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        contain top
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: contain; object-position: top;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        contain bottom
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: contain; object-position: bottom;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        contain center
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 72px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: contain; object-position: center;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        contain left
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 180px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: contain; object-position: left;"
+          />
+        </picture>
+      </div>
+    </div>
+    <div
+      class="image-demo"
+      data-v-2d6651f5=""
+    >
+      <p
+        class="image-demo-tip"
+        data-v-2d6651f5=""
+      >
+        contain right
+      </p>
+      <div
+        class="t-image t-image--square image-container"
+        data-v-2d6651f5=""
+        style="width: 180px; height: 80px;"
+      >
+        <div
+          class="t-image__mask"
+        >
+          <div
+            class="t-loading"
+            style="font-size: 20px;"
+          >
+            
+            <div
+              class="t-loading__dots"
+              style="animation-duration: 800ms; width: 20px; height: 20px;"
+            >
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.26666666666666666s;"
+              />
+              <div
+                class="t-loading__dot"
+                style="animation-duration: 0.8s; animation-delay: 0.5333333333333333s;"
+              />
+            </div>
+            
+            <!--v-if-->
+            <!---->
+          </div>
+        </div>
+        <picture>
+          <!--v-if-->
+          <img
+            alt=""
+            class="t-image__img"
+            src="https://tdesign.gtimg.com/demo/demo-image-1.png"
+            style="object-fit: contain; object-position: right;"
+          />
+        </picture>
+      </div>
+    </div>
+  </div>
+</div>
+`;
+
 exports[`Image > Image shapeVue demo works fine 1`] = `
 <div
   class="image-example"
diff --git a/src/image/__test__/demo.test.jsx b/src/image/__test__/demo.test.jsx
index 79a7fed5..aab66c30 100644
--- a/src/image/__test__/demo.test.jsx
+++ b/src/image/__test__/demo.test.jsx
@@ -5,12 +5,14 @@
 import { mount } from '@vue/test-utils';
 import baseVue from '@/image/demos/base.vue';
 import mobileVue from '@/image/demos/mobile.vue';
+import positionVue from '@/image/demos/position.vue';
 import shapeVue from '@/image/demos/shape.vue';
 import statusVue from '@/image/demos/status.vue';
 
 const mapper = {
   baseVue,
   mobileVue,
+  positionVue,
   shapeVue,
   statusVue,
 };
diff --git a/src/link/__test__/index.test.jsx b/src/link/__test__/index.test.jsx
index 7670afcc..e32bf68e 100644
--- a/src/link/__test__/index.test.jsx
+++ b/src/link/__test__/index.test.jsx
@@ -18,10 +18,10 @@ describe('Link', () => {
       expect(wrapper.find('.t-link--large').exists()).toBeTruthy();
       const wrapperDefault = mount({
         render() {
-          return <Link size=''>text</Link>;
+          return <Link size={''}>text</Link>;
         },
       });
-      expect(wrapperDefault.find('.t-link--').exists()).toBeTruthy();
+      expect(wrapperDefault.find('.t-link--medium').exists()).toBeTruthy();
     });
     it(':theme', () => {
       const wrapper = mount({
@@ -32,10 +32,10 @@ describe('Link', () => {
       expect(wrapper.find('.t-link--primary').exists()).toBeTruthy();
       const wrapperDefault = mount({
         render() {
-          return <Link theme=''>text</Link>;
+          return <Link theme={''}>text</Link>;
         },
       });
-      expect(wrapperDefault.find('.t-link--').exists()).toBeTruthy();
+      expect(wrapperDefault.find('.t-link--default').exists()).toBeTruthy();
     });
     it(':hover', () => {
       const wrapper = mount({
diff --git a/src/popover/__test__/__snapshots__/demo.test.jsx.snap b/src/popover/__test__/__snapshots__/demo.test.jsx.snap
new file mode 100644
index 00000000..871492cf
--- /dev/null
+++ b/src/popover/__test__/__snapshots__/demo.test.jsx.snap
@@ -0,0 +1,2218 @@
+// Vitest Snapshot v1
+
+exports[`Popover > Popover mobileVue demo works fine 1`] = `
+<div
+  class="tdesign-mobile-demo"
+  data-v-c909e4b8=""
+>
+  <h1
+    class="title"
+    data-v-c909e4b8=""
+  >
+    Popover 弹出气泡
+  </h1>
+  <p
+    class="summary"
+    data-v-c909e4b8=""
+  >
+    用于文字提示的气泡框。
+  </p>
+  <div
+    class="tdesign-mobile-demo-block"
+    data-v-c909e4b8=""
+  >
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <h2
+        class="tdesign-mobile-demo-block__title"
+      >
+        01 组件类型
+      </h2>
+      <!--v-if-->
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot"
+    >
+      
+      
+      <div
+        class="popover-example"
+        data-v-3b645a88=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-3b645a88=""
+        >
+          带箭头的弹出气泡
+        </div>
+        <div
+          class="popover-example__content mb-24"
+          data-v-3b645a88=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+              data-v-3b645a88=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                带箭头
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--dark"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-3b645a88=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-3b645a88=""
+        >
+          不带箭头的弹出气泡
+        </div>
+        <div
+          class="popover-example__content mb-24"
+          data-v-3b645a88=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+              data-v-3b645a88=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                不带箭头
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--dark"
+            >
+              弹出气泡内容
+              <!--v-if-->
+            </div>
+          </div>
+          
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-3b645a88=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-3b645a88=""
+        >
+          自定义内容弹出气泡
+        </div>
+        <div
+          class="custom popover-example__content mb-24"
+          data-v-3b645a88=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+              data-v-3b645a88=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                自定义内容
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--dark"
+            >
+              
+              <div
+                class="custom__list"
+                data-v-3b645a88=""
+              >
+                
+                <div
+                  class="custom__item"
+                  data-v-3b645a88=""
+                >
+                  选项1
+                </div>
+                <div
+                  class="custom__item"
+                  data-v-3b645a88=""
+                >
+                  选项2
+                </div>
+                <div
+                  class="custom__item"
+                  data-v-3b645a88=""
+                >
+                  选项3
+                </div>
+                
+              </div>
+              
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+      </div>
+      
+      
+    </div>
+  </div>
+  <div
+    class="tdesign-mobile-demo-block"
+    data-v-c909e4b8=""
+  >
+    <div
+      class="tdesign-mobile-demo-block__header"
+    >
+      <h2
+        class="tdesign-mobile-demo-block__title"
+      >
+        02 组件样式
+      </h2>
+      <!--v-if-->
+    </div>
+    <div
+      class="tdesign-mobile-demo-block__slot"
+    >
+      
+      
+      <div
+        class="popover-example"
+        data-v-4c211b37=""
+      >
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 深色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--dark"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 浅色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--light"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 品牌色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--brand"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-4c211b37=""
+      >
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 成功色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--success"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 警告色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--warning"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+        <div
+          class="popover-example__content"
+          data-v-4c211b37=""
+        >
+          
+          <div
+            class="t-popover__wrapper"
+          >
+            
+            <button
+              aria-disabled="false"
+              class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+              data-v-4c211b37=""
+              role="button"
+              type="button"
+            >
+              <!---->
+              <span
+                class="t-button__content"
+              >
+                
+                 错误色 
+                
+              </span>
+              <!---->
+            </button>
+            
+          </div>
+          <div
+            class="t-popover"
+            data-popper-placement=""
+            style="display: none;"
+          >
+            <div
+              class="t-popover__content t-popover--error"
+            >
+              弹出气泡内容
+              <div
+                class="t-popover__arrow"
+              />
+            </div>
+          </div>
+          
+        </div>
+      </div>
+      
+      
+    </div>
+  </div>
+  <div
+    class="tdesign-mobile-demo-block tdesign-mobile-demo-block_notitle"
+    data-v-c909e4b8=""
+  >
+    <!--v-if-->
+    <div
+      class="tdesign-mobile-demo-block__slot"
+    >
+      
+      
+      <div
+        class="popover-example"
+        data-v-5b842f53=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-5b842f53=""
+        >
+          顶部弹出气泡
+        </div>
+        <div
+          class="popover-example__content row mb-24"
+          data-v-5b842f53=""
+        >
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   顶部左 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   顶部中 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   顶部右 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-5b842f53=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-5b842f53=""
+        >
+          底部弹出气泡
+        </div>
+        <div
+          class="popover-example__content row mb-24"
+          data-v-5b842f53=""
+        >
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   底部左 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   底部中 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   底部右 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                弹出气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-5b842f53=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-5b842f53=""
+        >
+          右侧弹出气泡
+        </div>
+        <div
+          class="popover-example__content column mb-24"
+          data-v-5b842f53=""
+        >
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   右侧上 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   右侧中 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   右侧下 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+        </div>
+      </div>
+      <div
+        class="popover-example"
+        data-v-5b842f53=""
+      >
+        <div
+          class="popover-example__summary mb-16"
+          data-v-5b842f53=""
+        >
+          左侧弹出气泡
+        </div>
+        <div
+          class="popover-example__content column flex-end mb-24"
+          data-v-5b842f53=""
+        >
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   左侧上 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   左侧中 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+          <div
+            class="popover-example__content__item"
+            data-v-5b842f53=""
+          >
+            
+            <div
+              class="t-popover__wrapper"
+            >
+              
+              <button
+                aria-disabled="false"
+                class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+                data-v-5b842f53=""
+                role="button"
+                type="button"
+              >
+                <!---->
+                <span
+                  class="t-button__content"
+                >
+                  
+                   左侧下 
+                  
+                </span>
+                <!---->
+              </button>
+              
+            </div>
+            <div
+              class="t-popover"
+              data-popper-placement=""
+              style="display: none;"
+            >
+              <div
+                class="t-popover__content t-popover--dark"
+              >
+                气泡内容
+                <div
+                  class="t-popover__arrow"
+                />
+              </div>
+            </div>
+            
+          </div>
+        </div>
+      </div>
+      
+      
+    </div>
+  </div>
+</div>
+`;
+
+exports[`Popover > Popover placementVue demo works fine 1`] = `
+<div
+  data-v-app=""
+>
+  
+  <div
+    class="popover-example"
+    data-v-5b842f53=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-5b842f53=""
+    >
+      顶部弹出气泡
+    </div>
+    <div
+      class="popover-example__content row mb-24"
+      data-v-5b842f53=""
+    >
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               顶部左 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               顶部中 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               顶部右 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-5b842f53=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-5b842f53=""
+    >
+      底部弹出气泡
+    </div>
+    <div
+      class="popover-example__content row mb-24"
+      data-v-5b842f53=""
+    >
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               底部左 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               底部中 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               底部右 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            弹出气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-5b842f53=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-5b842f53=""
+    >
+      右侧弹出气泡
+    </div>
+    <div
+      class="popover-example__content column mb-24"
+      data-v-5b842f53=""
+    >
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               右侧上 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               右侧中 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               右侧下 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-5b842f53=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-5b842f53=""
+    >
+      左侧弹出气泡
+    </div>
+    <div
+      class="popover-example__content column flex-end mb-24"
+      data-v-5b842f53=""
+    >
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               左侧上 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               左侧中 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+      <div
+        class="popover-example__content__item"
+        data-v-5b842f53=""
+      >
+        
+        <div
+          class="t-popover__wrapper"
+        >
+          
+          <button
+            aria-disabled="false"
+            class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-with--large"
+            data-v-5b842f53=""
+            role="button"
+            type="button"
+          >
+            <!---->
+            <span
+              class="t-button__content"
+            >
+              
+               左侧下 
+              
+            </span>
+            <!---->
+          </button>
+          
+        </div>
+        <div
+          class="t-popover"
+          data-popper-placement=""
+          style="display: none;"
+        >
+          <div
+            class="t-popover__content t-popover--dark"
+          >
+            气泡内容
+            <div
+              class="t-popover__arrow"
+            />
+          </div>
+        </div>
+        
+      </div>
+    </div>
+  </div>
+  
+</div>
+`;
+
+exports[`Popover > Popover themeVue demo works fine 1`] = `
+<div
+  data-v-app=""
+>
+  
+  <div
+    class="popover-example"
+    data-v-4c211b37=""
+  >
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             深色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--dark"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             浅色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--light"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             品牌色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--brand"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-4c211b37=""
+  >
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             成功色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--success"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             警告色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--warning"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+    <div
+      class="popover-example__content"
+      data-v-4c211b37=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle button-width--small"
+          data-v-4c211b37=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+             错误色 
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--error"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+  </div>
+  
+</div>
+`;
+
+exports[`Popover > Popover typeVue demo works fine 1`] = `
+<div
+  data-v-app=""
+>
+  
+  <div
+    class="popover-example"
+    data-v-3b645a88=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-3b645a88=""
+    >
+      带箭头的弹出气泡
+    </div>
+    <div
+      class="popover-example__content mb-24"
+      data-v-3b645a88=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+          data-v-3b645a88=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+            带箭头
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--dark"
+        >
+          弹出气泡内容
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-3b645a88=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-3b645a88=""
+    >
+      不带箭头的弹出气泡
+    </div>
+    <div
+      class="popover-example__content mb-24"
+      data-v-3b645a88=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+          data-v-3b645a88=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+            不带箭头
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--dark"
+        >
+          弹出气泡内容
+          <!--v-if-->
+        </div>
+      </div>
+      
+    </div>
+  </div>
+  <div
+    class="popover-example"
+    data-v-3b645a88=""
+  >
+    <div
+      class="popover-example__summary mb-16"
+      data-v-3b645a88=""
+    >
+      自定义内容弹出气泡
+    </div>
+    <div
+      class="custom popover-example__content mb-24"
+      data-v-3b645a88=""
+    >
+      
+      <div
+        class="t-popover__wrapper"
+      >
+        
+        <button
+          aria-disabled="false"
+          class="t-button t-button--size-large t-button--outline t-button--primary t-button--rectangle"
+          data-v-3b645a88=""
+          role="button"
+          type="button"
+        >
+          <!---->
+          <span
+            class="t-button__content"
+          >
+            
+            自定义内容
+            
+          </span>
+          <!---->
+        </button>
+        
+      </div>
+      <div
+        class="t-popover"
+        data-popper-placement=""
+        style="display: none;"
+      >
+        <div
+          class="t-popover__content t-popover--dark"
+        >
+          
+          <div
+            class="custom__list"
+            data-v-3b645a88=""
+          >
+            
+            <div
+              class="custom__item"
+              data-v-3b645a88=""
+            >
+              选项1
+            </div>
+            <div
+              class="custom__item"
+              data-v-3b645a88=""
+            >
+              选项2
+            </div>
+            <div
+              class="custom__item"
+              data-v-3b645a88=""
+            >
+              选项3
+            </div>
+            
+          </div>
+          
+          <div
+            class="t-popover__arrow"
+          />
+        </div>
+      </div>
+      
+    </div>
+  </div>
+  
+</div>
+`;
diff --git a/src/popover/__test__/demo.test.jsx b/src/popover/__test__/demo.test.jsx
new file mode 100644
index 00000000..b6b732b2
--- /dev/null
+++ b/src/popover/__test__/demo.test.jsx
@@ -0,0 +1,25 @@
+/**
+ * 该文件为由脚本 `npm run test:demo` 自动生成，如需修改，执行脚本命令即可。请勿手写直接修改，否则会被覆盖
+ */
+
+import { mount } from '@vue/test-utils';
+import mobileVue from '@/popover/demos/mobile.vue';
+import placementVue from '@/popover/demos/placement.vue';
+import themeVue from '@/popover/demos/theme.vue';
+import typeVue from '@/popover/demos/type.vue';
+
+const mapper = {
+  mobileVue,
+  placementVue,
+  themeVue,
+  typeVue,
+};
+
+describe('Popover', () => {
+  Object.keys(mapper).forEach((demoName) => {
+    it(`Popover ${demoName} demo works fine`, () => {
+      const wrapper = mount(mapper[demoName]);
+      expect(wrapper.element).toMatchSnapshot();
+    });
+  });
+});
diff --git a/src/result/__test__/index.test.jsx b/src/result/__test__/index.test.jsx
index cac18d75..80bb5837 100644
--- a/src/result/__test__/index.test.jsx
+++ b/src/result/__test__/index.test.jsx
@@ -49,7 +49,8 @@ describe('Result.vue', () => {
     const wrapper1 = mount(() => <Result theme="success"></Result>);
     const wrapper2 = mount(() => <Result theme="warning"></Result>);
     const wrapper3 = mount(() => <Result theme="error"></Result>);
-    const wrapper4 = mount(() => <Result theme=""></Result>);
+    const wrapper4 = mount(() => <Result theme={''}></Result>);
+
 
     expect(wrapper1.classes()).toContain('t-result--theme-success');
     expect(wrapper1.findComponent(CheckCircleIcon).exists()).toBeTruthy();
@@ -58,6 +59,6 @@ describe('Result.vue', () => {
     expect(wrapper3.classes()).toContain('t-result--theme-error');
     expect(wrapper3.findComponent(CloseCircleIcon).exists()).toBeTruthy();
 
-    expect(wrapper4.classes()).toContain('t-result--theme-');
+    expect(wrapper4.classes()).toContain('t-result--theme-default');
   });
 });
diff --git a/src/textarea/__test__/index.test.jsx b/src/textarea/__test__/index.test.jsx
index fbc2d6ca..841b8617 100644
--- a/src/textarea/__test__/index.test.jsx
+++ b/src/textarea/__test__/index.test.jsx
@@ -25,9 +25,10 @@ describe('Textarea.vue', () => {
     const wrapper = mount(
       <Textarea label="标题" v-model={value.value} maxcharacter={maxcharacter} onChange={onChange} />,
     );
+    expect(onChange).toBeCalledTimes(1);
     const el = wrapper.find('textarea').element;
     await simulateEvent(el, '一个汉字等于两个字符，超出会被剪切', 'input');
-    expect(onChange).toBeCalledTimes(1);
+    expect(onChange).toBeCalledTimes(2);
     expect(onChange).toHaveBeenCalledWith('一');
   });
 
@@ -35,9 +36,10 @@ describe('Textarea.vue', () => {
     const value = ref('');
     const onChange = vi.fn();
     const wrapper = mount(<Textarea label="标题" v-model={value.value} autosize onChange={onChange} />);
+    expect(onChange).toBeCalledTimes(1);
     const el = wrapper.find('textarea').element;
     await simulateEvent(el, '这里是一段很长很长很长的长文本，支持自动换行', 'input');
-    expect(onChange).toBeCalledTimes(1);
+    expect(onChange).toBeCalledTimes(2);
   });
 
   it(': placeholder', async () => {