uniapp开发公众号,实现回到顶部功能

组件 my-back-to-top.vue

html 复制代码
<template>
	<view v-show="isShown" class="back-top" :style="rootStyle" @touchstart.stop="onTouchStart"
		  @touchmove.stop.prevent="onTouchMove" @touchend.stop="onTouchEnd" @click.stop="onClick">
		<up-icon name="arrow-up" :size="iconSize" :color="iconColor"></up-icon>
	</view>
</template>

<script setup>
/**
	通用组件:回到顶部(可拖拽悬浮按钮)

	实现要点(uni-app + Vue3 + uview-plus):
	1. 显隐控制:
		- 通过 onPageScroll 监听页面滚动,超过 visibleOffset 才显示(onlyShowWhenScroll=true)。
		- 如果 onlyShowWhenScroll=false,则初始就显示。
	2. 初始定位:
		- 组件记录中心点坐标 leftPx/topPx(单位:px),mounted 时读取系统窗口宽高,
			根据 initialRight/initialBottom 计算默认靠近右下的位置。
	3. 拖拽移动:
		- touchstart 记录起点与当前中心点;touchmove 计算位移增量,更新 leftPx/topPx。
		- clamp 辅助:约束在安全边界内(避免超出屏幕和状态栏)。
	4. 样式计算:
		- 使用 computed 拼出内联样式,将中心点还原为 left/top(左上角)并设置 size、圆角、阴影、zIndex 等。
	5. 回到顶部:
		- click 时调用 uni.pageScrollTo({ scrollTop: 0, duration }) 平滑回到顶部;
		- 若刚发生拖拽且位移较大,短时间内点击将被忽略,避免误触。
	6. UI:
		- 图标用 uview-plus 的 u-icon(arrow-up)。支持自定义尺寸与渐变背景。
*/
import { ref, onMounted, computed } from 'vue'
import { onPageScroll } from '@dcloudio/uni-app'

const props = defineProps({
	// 显示滚动距离阈值,超过才显示
	visibleOffset: { type: Number, default: 300 },
	// 初始距右侧 px
	initialRight: { type: Number, default: 24 },
	// 初始距底部 px
	initialBottom: { type: Number, default: 120 },
	// 直径 px
	size: { type: Number, default: 48 },
	// 图标大小 px
	iconSize: { type: Number, default: 22 },
	// 图标颜色
	iconColor: { type: String, default: '#ffffff' },
	// 背景色
	backgroundColor: { type: String, default: 'linear-gradient(90deg, #FF0D01 0%, #FE634B 100%)' },
	// 阴影
	boxShadow: { type: String, default: '0 6px 16px rgba(0,0,0,0.15)' },
	// 层级
	zIndex: { type: Number, default: 999 },
	// 是否仅滚动后显示
	onlyShowWhenScroll: { type: Boolean, default: true },
	// 是否禁用拖拽
	disableDrag: { type: Boolean, default: false }
})

// 运行环境窗口信息(用于定位与边界计算)
const windowWidth = ref(375)
const windowHeight = ref(667)
const statusBarHeight = ref(0)

// 显隐与中心点坐标(单位:px)
const isShown = ref(!props.onlyShowWhenScroll)
const leftPx = ref(0)
const topPx = ref(0)

// 拖拽状态缓存
const touching = ref(false)
const startTouch = ref({ x: 0, y: 0, t: 0, left: 0, top: 0 })

onMounted(() => {
	const info = uni.getSystemInfoSync()
	windowWidth.value = info.windowWidth
	windowHeight.value = info.windowHeight
	statusBarHeight.value = info.statusBarHeight || 0

	// 计算初始位置(默认靠右下:距右 initialRight、距底 initialBottom)
	const sizeHalf = props.size / 2
	leftPx.value = Math.max(
		sizeHalf,
		Math.min(windowWidth.value - sizeHalf, windowWidth.value - props.initialRight - sizeHalf)
	)
	topPx.value = Math.max(
		statusBarHeight.value + sizeHalf,
		Math.min(windowHeight.value - sizeHalf, windowHeight.value - props.initialBottom - sizeHalf)
	)
})

onPageScroll((e) => {
	if (!props.onlyShowWhenScroll) return
	isShown.value = e.scrollTop >= props.visibleOffset
})

// 由中心点生成用于视图的定位与样式
const rootStyle = computed(() => {
	return `
		left:${leftPx.value - props.size / 2}px;
		top:${topPx.value - props.size / 2}px;
		width:${props.size}px;
		height:${props.size}px;
		background:${props.backgroundColor};
		box-shadow:${props.boxShadow};
		z-index:${props.zIndex};
	`
})

// 将值限制在[min, max] 区间
function clamp(val, min, max) {
	return Math.max(min, Math.min(max, val))
}

// 开始拖拽:记录触点与初始位置
function onTouchStart(ev) {
	if (props.disableDrag) return
	touching.value = true
	const t = (ev.touches && ev.touches[0]) || ev
	startTouch.value = {
		x: t.clientX,
		y: t.clientY,
		t: Date.now(),
		left: leftPx.value,
		top: topPx.value
	}
}

// 拖拽移动:根据位移增量更新中心点,并做边界约束
function onTouchMove(ev) {
	if (!touching.value || props.disableDrag) return
	const t = (ev.touches && ev.touches[0]) || ev
	const dx = t.clientX - startTouch.value.x
	const dy = t.clientY - startTouch.value.y
	const sizeHalf = props.size / 2
	leftPx.value = clamp(
		startTouch.value.left + dx,
		sizeHalf,
		windowWidth.value - sizeHalf
	)
	topPx.value = clamp(
		startTouch.value.top + dy,
		statusBarHeight.value + sizeHalf,
		windowHeight.value - sizeHalf
	)
}

// 结束拖拽:如需吸附/惯性,可在此扩展
function onTouchEnd() {
	if (props.disableDrag) return
	touching.value = false
}

// 点击回到顶部,防抖:刚拖拽且位移大时忽略点击
function onClick() {
	// 如果刚拖拽结束且位移较大,忽略点击
	if (startTouch.value) {
		const moved = Math.abs(leftPx.value - startTouch.value.left) + Math.abs(topPx.value - startTouch.value.top)
		if (moved > 6 && Date.now() - startTouch.value.t < 300) return
	}
	uni.pageScrollTo({ scrollTop: 0, duration: 300 })
}
</script>

<style scoped>
.back-top {
	position: fixed;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 9999px;
	user-select: none;
	-webkit-user-drag: none;
	transition: opacity 0.2s ease;
}

.gradient-icon {
	background: linear-gradient(90deg, #FF0D01 0%, #FE634B 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}
</style>

通用组件:回到顶部 components/my-back-to-top.vue

可拖拽、圆形悬浮按钮,默认位于右下方,滚动超阈值显示,点击回到顶部。

使用示例:

html 复制代码
<template>
  <view>
    <!-- 页面内容 ... -->
    <my-back-to-top />
  </view>
</template>

<script setup>
import MyBackToTop from "@/components/my-back-to-top.vue";
</script>

可选属性:

  • visibleOffset 滚动多少像素后显示(默认 300)
  • initialRight 初始距右侧 px(默认 24)
  • initialBottom 初始距底部 px(默认 120)
  • size 直径 px(默认 48)
  • iconSize 图标大小 px(默认 22)
  • iconColor 图标颜色(默认 #ffffff
  • backgroundColor 背景色(默认 #2979ff
  • boxShadow 阴影(默认 0 6px 16px rgba(0,0,0,0.15)
  • zIndex 层级(默认 999)
  • onlyShowWhenScroll 仅滚动后显示(默认 true)
  • disableDrag 禁用拖拽(默认 false)

示例(自定义样式):

html 复制代码
<my-back-to-top
  :visibleOffset="400"
  :size="56"
  :iconSize="24"
  backgroundColor="#ff6a00"
/>

这里显示的图标是uview-plus里的图标,想要好看一点的可以下载更换成其他字体图标调整样式就行,功能已经完成

相关推荐
半开半落2 小时前
uniapp微信小程序端接收ai模型返回的SSE流式数据
微信小程序·小程序·uni-app·ai模型
2501_916007473 小时前
在 CICD 中实践 Fastlane + Appuploader 命令行,构建可复制的 iOS 自动化发布流程
android·运维·ios·小程序·uni-app·自动化·iphone
qq_316837753 小时前
uniapp 缓存指定接口的响应,在无网络时使用缓存数据
前端·uni-app
奺儿3 小时前
uniapp 小程序 报错 TypeError: Cannot convert undefined or null to object
小程序·uni-app
2501_915921433 小时前
从 HBuilder 到 App Store,uni-app 与 HBuilder 项目的 iOS 上架流程实战解析
android·ios·小程序·https·uni-app·iphone·webview
qq_316837753 小时前
uniapp 缓存请求文件时 判断是否有文件缓存 并下载和使用
前端·缓存·uni-app
随笔记4 小时前
uniapp开发app使用海康威视播放监控视频流如何使用以及遇到了什么问题
vue.js·uni-app·视频编码
游戏开发爱好者84 小时前
以 uni-app 为核心的 iOS 上架流程实践, 从构建到最终提交的完整路径
android·ios·小程序·https·uni-app·iphone·webview
游戏开发爱好者85 小时前
构建可落地的 iOS 性能测试体系,从场景拆解到多工具协同的工程化实践
android·ios·小程序·https·uni-app·iphone·webview