Skip to content

Popover 气泡

介绍

Popover 气泡组件用于展示弹出式的提示信息或操作菜单。相比 Tooltip,Popover 更适合展示复杂内容或操作列表,支持普通模式和菜单模式两种展示形式。

核心特性:

  • 双模式支持 - 普通模式和菜单模式
  • 多方位弹出 - 支持 12 种弹出位置
  • 菜单图标 - 菜单项支持图标展示
  • 自定义内容 - 支持插槽完全自定义
  • 受控模式 - 支持 v-model 控制显示状态

基本用法

普通模式

默认为普通模式,通过 content 属性设置文本内容。

vue
<template>
  <wd-popover content="这是一段普通文本提示">
    <wd-button>点击显示</wd-button>
  </wd-popover>
</template>

菜单模式

设置 mode="menu" 启用菜单模式,content 传入菜单项数组。

vue
<template>
  <wd-popover mode="menu" :content="menuList" @menuclick="handleMenuClick">
    <wd-button>菜单模式</wd-button>
  </wd-popover>
</template>

<script lang="ts" setup>
const menuList = [
  { content: '选项一' },
  { content: '选项二' },
  { content: '选项三' }
]

const handleMenuClick = ({ item, index }) => {
  console.log('点击菜单项:', item, index)
}
</script>

带图标的菜单

菜单项支持 iconClass 属性设置图标。

vue
<template>
  <wd-popover mode="menu" :content="iconMenuList" @menuclick="handleMenuClick">
    <wd-button>带图标菜单</wd-button>
  </wd-popover>
</template>

<script lang="ts" setup>
const iconMenuList = [
  { content: '编辑', iconClass: 'edit' },
  { content: '删除', iconClass: 'delete' },
  { content: '分享', iconClass: 'share' }
]

const handleMenuClick = ({ item, index }) => {
  uni.showToast({ title: item.content, icon: 'none' })
}
</script>

弹出位置

通过 placement 设置弹出位置。

vue
<template>
  <wd-popover content="顶部弹出" placement="top">
    <wd-button>上</wd-button>
  </wd-popover>

  <wd-popover content="底部弹出" placement="bottom">
    <wd-button>下</wd-button>
  </wd-popover>

  <wd-popover content="左侧弹出" placement="left">
    <wd-button>左</wd-button>
  </wd-popover>

  <wd-popover content="右侧弹出" placement="right">
    <wd-button>右</wd-button>
  </wd-popover>
</template>

受控模式

通过 v-model 控制气泡的显示状态。

vue
<template>
  <wd-popover v-model="visible" content="受控模式">
    <wd-button>{{ visible ? '点击关闭' : '点击打开' }}</wd-button>
  </wd-popover>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const visible = ref(false)
</script>

显示关闭按钮

设置 show-close 显示关闭按钮。

vue
<template>
  <wd-popover content="带关闭按钮的气泡" show-close>
    <wd-button>显示关闭按钮</wd-button>
  </wd-popover>
</template>

隐藏箭头

设置 visible-arrowfalse 隐藏箭头。

vue
<template>
  <wd-popover content="无箭头气泡" :visible-arrow="false">
    <wd-button>隐藏箭头</wd-button>
  </wd-popover>
</template>

自定义内容

通过 content 插槽自定义气泡内容。

vue
<template>
  <wd-popover use-content-slot>
    <template #content>
      <view class="custom-popover">
        <image src="/static/avatar.png" class="avatar" />
        <view class="info">
          <text class="name">用户名</text>
          <text class="desc">这是个人简介</text>
        </view>
      </view>
    </template>
    <wd-button>自定义内容</wd-button>
  </wd-popover>
</template>

<style lang="scss" scoped>
.custom-popover {
  display: flex;
  align-items: center;
  padding: 16rpx;

  .avatar {
    width: 80rpx;
    height: 80rpx;
    border-radius: 50%;
  }

  .info {
    margin-left: 16rpx;

    .name {
      font-size: 28rpx;
      font-weight: bold;
    }

    .desc {
      font-size: 24rpx;
      color: #999;
    }
  }
}
</style>

禁用状态

设置 disabled 禁用气泡。

vue
<template>
  <wd-popover content="禁用状态" disabled>
    <wd-button>禁用的气泡</wd-button>
  </wd-popover>
</template>

方法调用

通过 ref 获取组件实例,调用 open/close 方法。

vue
<template>
  <wd-popover ref="popoverRef" content="方法控制">
    <wd-button>目标元素</wd-button>
  </wd-popover>
  <wd-button @click="handleOpen">打开</wd-button>
  <wd-button @click="handleClose">关闭</wd-button>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const popoverRef = ref()

const handleOpen = () => {
  popoverRef.value?.open()
}

const handleClose = () => {
  popoverRef.value?.close()
}
</script>

API

Props

参数说明类型默认值
v-model是否显示booleanfalse
mode展示模式'normal' | 'menu'normal
content显示内容(普通模式为字符串,菜单模式为数组)string | MenuItem[]-
placement弹出位置PlacementTypebottom
offset偏移量number0
visible-arrow是否显示箭头booleantrue
use-content-slot是否使用 content 插槽booleanfalse
disabled是否禁用booleanfalse
show-close是否显示关闭按钮booleanfalse
custom-class自定义根节点样式类string-
custom-style自定义根节点样式string-
custom-arrow自定义箭头样式类string-
custom-pop自定义弹出层样式类string-

Events

事件名说明回调参数
change显示状态变化时触发{ show: boolean }
open打开时触发-
close关闭时触发-
menuclick菜单项点击时触发(仅菜单模式){ item: MenuItem, index: number }

Slots

名称说明
default触发气泡的元素
content自定义气泡内容

Methods

方法名说明参数返回值
open打开气泡--
close关闭气泡--

类型定义

typescript
/**
 * 弹出位置类型
 */
type PlacementType =
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end'
  | 'right'
  | 'right-start'
  | 'right-end'

/**
 * 菜单项类型
 */
interface MenuItem {
  /** 菜单项内容 */
  content: string
  /** 图标类名 */
  iconClass?: string
}

主题定制

组件提供了以下 CSS 变量用于主题定制:

变量名说明默认值
--wd-popover-bg背景颜色#ffffff
--wd-popover-color文字颜色#333333
--wd-popover-fs字体大小28rpx
--wd-popover-padding内边距24rpx
--wd-popover-radius圆角8rpx
--wd-popover-line-height行高40rpx
--wd-popover-z-index层级500
--wd-popover-box-shadow阴影0 4rpx 20rpx rgba(0, 0, 0, 0.1)

最佳实践

1. 操作菜单

vue
<template>
  <wd-popover
    mode="menu"
    :content="actionMenu"
    placement="bottom-end"
    @menuclick="handleAction"
  >
    <wd-icon name="more" size="48rpx" />
  </wd-popover>
</template>

<script lang="ts" setup>
const actionMenu = [
  { content: '编辑', iconClass: 'edit' },
  { content: '复制', iconClass: 'copy' },
  { content: '删除', iconClass: 'delete' }
]

const handleAction = ({ item, index }) => {
  switch (index) {
    case 0:
      // 编辑
      break
    case 1:
      // 复制
      break
    case 2:
      // 删除
      break
  }
}
</script>

2. 用户信息卡片

vue
<template>
  <wd-popover use-content-slot placement="bottom-start">
    <template #content>
      <view class="user-card">
        <image :src="userInfo.avatar" class="avatar" />
        <view class="info">
          <text class="name">{{ userInfo.name }}</text>
          <text class="role">{{ userInfo.role }}</text>
        </view>
        <wd-button size="small" type="primary" @click="handleFollow">
          关注
        </wd-button>
      </view>
    </template>
    <text class="username">@{{ userInfo.name }}</text>
  </wd-popover>
</template>

3. 筛选菜单

vue
<template>
  <wd-popover
    mode="menu"
    :content="filterOptions"
    @menuclick="handleFilter"
  >
    <view class="filter-btn">
      <text>{{ currentFilter }}</text>
      <wd-icon name="arrow-down" />
    </view>
  </wd-popover>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const currentFilter = ref('全部')
const filterOptions = [
  { content: '全部' },
  { content: '待处理' },
  { content: '已完成' }
]

const handleFilter = ({ item }) => {
  currentFilter.value = item.content
}
</script>

常见问题

1. 菜单项点击后气泡不关闭?

组件默认点击菜单项后会自动关闭,如果没有关闭,检查是否阻止了事件冒泡。

2. 自定义内容样式不生效?

确保使用了 use-content-slot 属性,并在 content 插槽中添加内容。

3. 气泡位置不正确?

检查触发元素是否有正确的尺寸,以及父容器是否有 overflow: hidden

4. 普通模式和菜单模式的区别?

  • 普通模式: content 为字符串,适合展示简单文本
  • 菜单模式: content 为数组,适合展示操作列表
移动端预览