更新记录

1.0.0(2026-06-15)

  • 首发:uni-app x 应用内悬浮窗组件 ba-float-u(Android / iOS / Harmony)
  • 页面内悬浮:slot 自定义、拖拽、贴边吸附、遮罩弹层(placement=center)
  • 全局跨页悬浮:showGlobalFloat / updateGlobalFloat / hideGlobalFloat + ba-float-global-host
  • 内置 ba-float-global-shell(ball / bar)及 6 个独立预设组件 ba-float-preset-*
  • 手势:原生 longpress + touch 拖动 + tap 守卫,区分单击/长按/拖动
  • 全局 slot 自定义 UI;预设按需 import,业务侧自由组合
  • 全局 content 仅 type / icon / text / backgroundColor,角标由 preset 或自定义 UI 自行扩展

平台兼容性

uni-app(3.7.12)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(3.7.12)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - -

ba-float-u 应用内悬浮窗

简介

ba-float-u 是面向 uni-app x App 端(Android / iOS / Harmony)的应用内悬浮窗组件。

  • 页面内悬浮:写在当前页 template,随页面销毁
  • 全局跨页悬浮showGlobalFloat() + 各页 <ba-float-global-host />,切换页面仍显示
  • slot 自定义 UI:任意布局;内置 shell 与 6 个经典预设皮肤
  • 动态更新updateGlobalFloat() 不关闭悬浮即可更新 icon / text / backgroundColor 等
  • 手势:拖动、单击、长按统一识别,减少误触
模式 用法 跨页面 自定义 UI
全局悬浮 showGlobalFloat() + <ba-float-global-host /> slot / 预设组件
页面内悬浮 <ba-float-u> + slot slot

安装

  1. 在 HBuilderX 插件市场导入 ba-float-u,或
  2. uni_modules/ba-float-u 目录拷贝到项目的 uni_modules/

组件通过 easycom 自动引入,一般无需手动 import 组件标签。

平台与限制

说明
支持平台 uni-app x App:Android、iOS、Harmony
不支持 小程序、Web、传统 uni-app(非 x)
悬浮类型 应用内 fixed 层,非 Android 系统悬浮窗(无需 SYSTEM_ALERT_WINDOW
全局跨页 每个需要显示全局悬浮的页面根级须放同一个业务宿主(如 ba-app-global-float-host
跨页一致 各页若用不同 slot / 仅默认 shell,切换页面后 UI 与点击行为会不一致
多实例 全局同时仅 1 个;页面内可多个 <ba-float-u>
preset 依赖 ba-float-preset-* 读取 floatGlobalState,仅用于全局悬浮 slot
split 预设 视觉分区展示,拖动手势仍由外层 ba-float-u 统一识别
toolbar 预设 三个按钮为整体 UI,暂不支持单独点击各按钮

不要用 dialogPage 做全局悬浮:dialogPage 在 App 端为全屏层,会挡住下层页面所有点击。


一、全局悬浮(跨页面)

1. 页面根级放置宿主

<template>
  <view class="page">
    <!-- 页面内容 -->
    <ba-float-global-host />
  </view>
</template>

2. 显示 / 隐藏

import { showGlobalFloat, hideGlobalFloat, updateGlobalFloat } from '@/uni_modules/ba-float-u'

// 显示
showGlobalFloat({
  x: 20,
  y: 180,
  snap: 'edge',
  content: {
    type: 'ball',
    icon: '◎',
    backgroundColor: '#ff5722'
  }
})

// 动态更新(无需关闭)
updateGlobalFloat({
  content: {
    text: '正在播放',
    backgroundColor: '#1db954'
  }
})

hideGlobalFloat()

切换页面后,只要目标页也有 <ba-float-global-host />,悬浮会继续显示,且页面可正常点击

3. 全局 API

API 说明
showGlobalFloat(options?) 显示全局悬浮
updateGlobalFloat(options) 更新配置(位置、content 等),保持显示
hideGlobalFloat() 隐藏
isGlobalFloatVisible() 是否显示中
floatGlobalState 响应式全局状态(只读使用为主)

导出类型(TypeScript / UTS):

类型 说明
ShowGlobalFloatOptions showGlobalFloat / updateGlobalFloat 参数
GlobalFloatContentOptions content 可选字段
GlobalFloatContent floatGlobalState.content 结构
GlobalFloatState 完整全局状态
GlobalFloatSnap 贴边模式枚举

showGlobalFloat / updateGlobalFloat 参数:

参数 类型 说明
x number 初始 x 坐标
y number 初始 y 坐标
draggable boolean 是否可拖拽,默认 true
snap string 贴边:none / edge / horizontal / vertical
edgeMargin number 贴边留白(px),默认 10
clickThrough boolean 全局 host 内部固定为 true
content object 展示数据,见下表

content 字段:

字段 类型 说明
type string shell 模式:ball / bar;业务侧 preset 路由可自定义
icon string 图标/emoji
text string 文案
backgroundColor string 背景色

全局 content 不包含角标。红点/数字角标请在 slot 自定义 UI 或复制 preset 后自行扩展。

4. 自定义全局 UI(slot)

方式 A:直接传 slot

<ba-float-global-host>
  <view class="my-global-ball">
    <text>拖我</text>
  </view>
</ba-float-global-host>

未传 slot 时,使用内置 ba-float-global-shellcontent.typeball / bar)。

方式 B:按需引入预设组件

预设为独立组件,在 slot 中按需组合,只 import 用到的 preset:

<ba-float-global-host>
  <ba-float-preset-capsule />
</ba-float-global-host>
组件 典型场景
ba-float-global-shell 圆形球 ball / 文字条 bar(默认)
ba-float-preset-capsule 图标 + 文字胶囊
ba-float-preset-fab Extended FAB
ba-float-preset-edge 贴边半圆标签
ba-float-preset-split 左侧拖柄 + 右侧点击区(视觉)
ba-float-preset-toolbar 竖向迷你工具条
ba-float-preset-pill 直播/音乐小横条

方式 C:运行时切换多种预设(业务侧封装)

在工程中自建宿主,只 import 需要的 preset:

<template>
  <ba-float-global-host>
    <ba-float-preset-capsule v-if="presetType == 'capsule'" />
    <ba-float-preset-fab v-else-if="presetType == 'fab'" />
    <ba-float-global-shell v-else />
  </ba-float-global-host>
</template>

<script lang="uts">
import BaFloatGlobalHost from '@/uni_modules/ba-float-u/components/ba-float-global-host/ba-float-global-host.uvue'
import BaFloatPresetCapsule from '@/uni_modules/ba-float-u/components/ba-float-preset-capsule/ba-float-preset-capsule.uvue'
import BaFloatPresetFab from '@/uni_modules/ba-float-u/components/ba-float-preset-fab/ba-float-preset-fab.uvue'
import BaFloatGlobalShell from '@/uni_modules/ba-float-u/components/ba-float-global-shell/ba-float-global-shell.uvue'
import { floatGlobalState } from '@/uni_modules/ba-float-u'

export default {
  components: { BaFloatGlobalHost, BaFloatPresetCapsule, BaFloatPresetFab, BaFloatGlobalShell },
  computed: {
    presetType(): string {
      return floatGlobalState.content.type
    }
  }
}
</script>

切换预设时调用 updateGlobalFloat({ content: { type: 'capsule', ... } }) 即可。

方式 D:封装固定 UI 各页复用(跨页一致,强烈推荐)

各页面必须使用同一个宿主,否则切换页面后 slot / 交互会不一致:

<!-- components/ba-app-global-float-host/ba-app-global-float-host.uvue -->
<template>
  <ba-float-global-host>
    <!-- 按 floatGlobalState.content.type 渲染 preset / 自定义 UI -->
    <ba-float-preset-capsule v-if="presetType == 'capsule'" />
    <ba-float-global-shell v-else />
  </ba-float-global-host>
</template>

各页面根级统一:

<ba-app-global-float-host />

跳转、多按钮等交互应在 App 级单例 或业务宿主内注册 uni.$on(演示见 utils/baFloatGlobalEvents.uts + App.uvue),切勿在页面 onUnload 里无参调用 uni.$off('ba-float-global-tap'),否则会清掉其它页的监听。

方式 E:slot 内自行加角标/扩展 UI

<ba-float-global-host>
  <view class="my-ball">
    <text>{{ floatGlobalState.content.icon }}</text>
    <view v-if="unread > 0" class="my-badge">
      <text>{{ unread }}</text>
    </view>
  </view>
</ba-float-global-host>

unread 绑定业务 store / data,与 updateGlobalFloat 更新的 content 字段互不冲突。

slot 内 不要@tap / @longpress,请监听组件 @tap / @long-press 或全局 uni.$on

5. 全局事件

uni.$on('ba-float-global-tap', (content) => {})
uni.$on('ba-float-global-long-press', (content) => {})
uni.$on('ba-float-global-drag-end', (e) => {})

// 页面卸载时记得 $off

二、页面内悬浮

无遮罩(悬浮球):只渲染 fixed 悬浮体,不铺全屏,页面可正常点击。

<ba-float-u v-model:visible="show" draggable snap="edge">
  <view class="my-float">...</view>
</ba-float-u>

带遮罩(弹层卡片):

<ba-float-u
  v-model:visible="showCard"
  mask
  placement="center"
  :draggable="false"
  @close="showCard = false"
>
  <view class="card">...</view>
</ba-float-u>

ba-float-u Props

Prop 类型 默认值 说明
visible / v-model:visible boolean false 是否显示
x number 20 横坐标(placement=free 时有效)
y number 100 纵坐标
draggable boolean true 是否可拖拽
snap string none 贴边:none / edge / horizontal / vertical
placement string free free 自由坐标;center 遮罩下居中
edgeMargin number 12 贴边留白(px)
zIndex number 999 层级
mask boolean false 是否显示遮罩
maskColor string rgba(0,0,0,0.35) 遮罩颜色
maskClosable boolean true 点击遮罩是否关闭
boundToScreen boolean true 是否限制在屏幕安全区内
dragThreshold number 5 拖动判定阈值(px)
clickThrough boolean true 已废弃,无遮罩时默认不挡点击

ba-float-u 事件

事件 说明
@tap 单击(无拖动、无长按)
@long-press 长按(无拖动)
@drag-start 开始拖动
@drag-end 拖动结束,参数含 x/y
@close 遮罩关闭时
@update:visible v-model 同步

四、交互示例

单击跳转页面(可拖动悬浮)

监听全局 uni.$on('ba-float-global-tap'),在回调里 uni.navigateTo

uni.$on('ba-float-global-tap', () => {
  uni.navigateTo({ url: '/pages/detail/detail' })
})

slot 内不要绑 @tap,统一走组件 / 全局事件。

slot 内多按钮(不可拖动)

设置 draggable: false 后,slot 内各按钮可独立 @click

showGlobalFloat({ draggable: false, snap: 'none' })
<ba-float-global-host>
  <view class="toolbar">
    <view @click="onHome">首页</view>
    <view @click="onNotify">通知</view>
  </view>
</ba-float-global-host>

五、手势说明

手势 识别方式
拖动 touchmove 位移 ≥ dragThreshold(默认 5px)
长按 系统 @longpress(约 350ms),且位移 < 2px
单击 系统 @tap,且本次无拖动、无长按

六、常见问题

Q:切换页面后悬浮 UI 变了 / 不能点击?
A:常见原因:① 各页 host 不一致(演示页有 preset slot,其它页只有默认 shell);② 单击/跳转的 uni.$on 只写在某一页,离开该页后失效;③ 多按钮模式须 draggable: false,但其它页 host 未渲染按钮 slot。
解决:封装统一业务宿主 + 在 App.onLaunch 注册全局 uni.$on(演示工程 initBaFloatGlobalEvents())。页面卸载时 $off 必须传入同一函数引用,禁止无参 $off 清空全部监听。

Q:全局悬浮切页面后消失了?
A:目标页面根级缺少 <ba-float-global-host />

Q:拖动时触发了点击?
A:slot 内不要绑 @tap;监听组件的 @tap 事件。若仍不满意,可考虑业务侧分区 UI(见 split 预设)。

Q:能否悬浮在其它 App 上方?
A:不能。本插件为应用内悬浮,非系统级悬浮窗。

Q:能否同时显示多个全局悬浮?
A:全局模式仅支持 1 个实例。页面内可同时使用多个 <ba-float-u>

Q:如何加角标/红点?
A:在 slot 自定义 UI 或复制 preset 到业务目录后自行布局,绑定业务数据即可(见上文「方式 E」)。

Q:是否支持微信小程序?
A:不支持。仅 uni-app x App 端(Android / iOS / Harmony)。


更新日志

changelog.md

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无额外权限(应用内 fixed 层,非系统悬浮窗权限)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。