ActivityFloatButton 悬浮活动按钮组件代码
当前说项目活动悬浮窗,点击跳转到活动页面,其他需求可重新更改当前组件
html
<template>
<view class="activity-float-button" :style="{
left: buttonX + 'px',
top: buttonY + 'px'
}" @touchstart.stop="handleTouchStart" @touchmove.stop="handleTouchMove" @touchend.stop="handleTouchEnd"
@click.stop="handleClick">
<image class="button-img" src="https://cdn.joytup.com/imgs/icon/cj.gif" mode="scaleToFill" />
<!-- <view class="button-text">活动</view> -->
</view>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
// 按钮尺寸
const BUTTON_WIDTH = 120 // 按钮宽度 rpx
const BUTTON_HEIGHT = 120 // 按钮高度 rpx
// 按钮位置
const buttonX = ref(0)
const buttonY = ref(0)
const isDragging = ref(false)
const startX = ref(0)
const startY = ref(0)
const offsetX = ref(0)
const offsetY = ref(0)
const hasMoved = ref(false)
const pixelRatio = ref(2)
// 获取系统信息
const getSystemInfo = () => {
return new Promise((resolve) => {
uni.getSystemInfo({
success: (res) => resolve(res),
fail: () => resolve({})
})
})
}
// 初始化按钮位置
const initPosition = async () => {
const systemInfo = await getSystemInfo()
const { windowWidth, windowHeight } = systemInfo
pixelRatio.value = 750 / windowWidth; // 推荐
// 将 rpx 转换为 px
const buttonWidthPx = BUTTON_WIDTH / 2 / pixelRatio.value * 2
const buttonHeightPx = BUTTON_HEIGHT / 2 / pixelRatio.value * 2
// 固定到右下角,留出安全边距
const margin = 40 / pixelRatio.value // px
const marginRight = 40 / 2 / pixelRatio.value * 2 // 右边缘留 40rpx
buttonX.value = windowWidth - buttonWidthPx - margin
buttonY.value = windowHeight - buttonHeightPx - margin
}
// 触摸开始
const handleTouchStart = (e) => {
isDragging.value = true
hasMoved.value = false
startX.value = e.touches[0].clientX
startY.value = e.touches[0].clientY
offsetX.value = buttonX.value
offsetY.value = buttonY.value
}
// 触摸移动
const handleTouchMove = (e) => {
if (!isDragging.value) return
e.preventDefault()
const clientX = e.touches[0].clientX
const clientY = e.touches[0].clientY
// 计算移动距离
const deltaX = clientX - startX.value
const deltaY = clientY - startY.value
// 判断是否真的移动了(避免点击时误判为拖动)
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
hasMoved.value = true
}
// 更新按钮位置
buttonX.value = offsetX.value + deltaX
buttonY.value = offsetY.value + deltaY
}
// 触摸结束,吸附到屏幕边缘
const handleTouchEnd = async () => {
isDragging.value = false
const systemInfo = await getSystemInfo()
const { windowWidth, windowHeight } = systemInfo
const buttonWidthPx = BUTTON_WIDTH / 2 / pixelRatio.value * 2
const buttonHeightPx = BUTTON_HEIGHT / 2 / pixelRatio.value * 2
const marginRight = 40 / 2 / pixelRatio.value * 2 // 右边缘留 40rpx
const centerX = buttonX.value + buttonWidthPx / 2
// 吸附到左边缘或右边缘
if (centerX < windowWidth / 2) {
buttonX.value = 10
} else {
console.log('右边:', windowWidth, buttonWidthPx, marginRight);
buttonX.value = windowWidth - buttonWidthPx - marginRight
}
// 限制 Y 轴范围,防止超出屏幕
const maxY = windowHeight - buttonHeightPx - 20 // 底部留 20px 边距
if (buttonY.value < 20) { // 顶部留 20px 边距
buttonY.value = 20
} else if (buttonY.value > maxY) {
buttonY.value = maxY
}
}
// 点击跳转
const handleClick = () => {
// 如果是拖动操作,不触发点击
if (hasMoved.value) return
uni.navigateTo({
url: '/pagesActivity/list/list'
})
}
onMounted(() => {
initPosition()
})
</script>
<style lang="scss" scoped>
.activity-float-button {
position: fixed;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
// cursor: pointer;
user-select: none;
// background: linear-gradient(135deg, #FF631B 0%, #FF8C42 100%);
// box-shadow: 0 4rpx 12rpx rgba(255, 99, 27, 0.3);
.button-img {
width: 120rpx;
height: 120rpx;
}
.button-text {
font-size: 28rpx;
font-weight: 500;
color: #FFFFFF;
text-align: center;
line-height: 1;
}
}
</style>
ActivityFloatButton 悬浮活动按钮组件文档
一个固定在页面右下角的可拖动悬浮按钮组件,用于快速跳转到活动列表页面。
功能特性
- ✅ 固定在页面右下角显示
- ✅ 支持触摸拖动,可自由移动位置
- ✅ 拖动结束后自动吸附到屏幕边缘
- ✅ 圆形渐变样式,美观大方
- ✅ 点击跳转到活动列表页面
- ✅ 区分拖动和点击操作,避免误触
- ✅ 自动适配不同屏幕尺寸
使用方法
1. 引入组件
html
<script setup>
import ActivityFloatButton from "@/components/activity-float-button/activity-float-button.vue";
</script>
2. 使用组件
html
<template>
<view class="page">
<!-- 你的页面内容 -->
<!-- 悬浮活动按钮 -->
<ActivityFloatButton />
</view>
</template>
<script setup>
import ActivityFloatButton from "@/components/activity-float-button/activity-float-button.vue";
</script>
3. 全局使用(推荐)
在 App.vue 中引入,即可在所有页面使用:
html
<template>
<view>
<!-- 你的全局内容 -->
<router-view />
<!-- 悬浮活动按钮 -->
<ActivityFloatButton />
</view>
</template>
<script setup>
import ActivityFloatButton from "@/components/activity-float-button/activity-float-button.vue";
</script>
组件样式
默认样式
- 尺寸:100rpx × 100rpx
- 形状:圆形
- 背景:橙色渐变(#FF631B → #FF8C42)
- 文字:白色,28rpx,居中显示"活动"
- 阴影:橙色半透明阴影,提升立体感
自定义样式
如需自定义样式,可以修改组件的样式部分:
css
.activity-float-button {
width: 120rpx; // 自定义宽度
height: 120rpx; // 自定义高度
background: linear-gradient(135deg, #007aff 0%, #5ac8fa 100%); // 自定义背景色
.button-text {
font-size: 32rpx; // 自定义文字大小
}
}
交互说明
拖动规则
- 长按并拖动可移动按钮位置
- 拖动结束后自动吸附到最近的屏幕边缘(左边缘或右边缘)
- 按钮不会超出屏幕边界
点击规则
- 纯点击:跳转到
/pagesActivity/list/list页面 - 拖动后松开:不触发跳转
跳转路径
默认跳转到 pagesActivity/list/list 页面,如需修改跳转路径,请编辑组件源码中的 handleClick 方法:
javascript
const handleClick = () => {
if (hasMoved.value) return;
uni.navigateTo({
url: "/your/custom/path", // 修改为你想要的跳转路径
});
};
技术实现
核心逻辑
- 定位 :使用
position: fixed固定定位 - 拖动 :通过
touchstart、touchmove、touchend事件实现 - 吸附:计算屏幕中心点,判断吸附到左边缘或右边缘
- 边界限制:防止按钮超出屏幕可视区域
- 操作区分:通过移动距离判断是拖动还是点击
注意事项
- 组件使用
uni.navigateTo进行页面跳转 - 按钮层级
z-index: 9999,确保在最上层显示 - 支持小程序和 H5 平台
兼容性
- ✅ 微信小程序
- ✅ H5
- ✅ 其他 uni-app 支持的平台
示例效果
Q: 按钮遮挡了页面内容怎么办?
A: 长按按钮并拖动到其他位置即可,按钮会自动吸附到屏幕边缘。
Q: 如何修改按钮文字?
A: 编辑组件模板中的 .button-text 内容即可。
Q: 如何在特定页面隐藏按钮?
A: 使用 v-if 或 v-show 控制组件的显示:
html
<ActivityFloatButton v-if="showButton" />
Q: 拖动后位置会保存吗?
A: 当前版本拖动后位置不会持久化保存,刷新页面会重置到右下角。如需保存位置,可以使用 uni.setStorageSync 存储。