更新记录
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 |
安装
- 在 HBuilderX 插件市场导入
ba-float-u,或 - 将
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-shell(content.type 为 ball / 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)。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 14381
赞赏 6
下载 12251488
赞赏 1922
赞赏
京公网安备:11010802035340号