Uniapp全局显示 悬浮组件/无需单页面引入

一、创建一个悬浮组件,代码示例如下,根据自己情况而定。

html 复制代码
<template>
	<view class="hover-ball" :style="ballStyle" @touchstart="handleTouchStart" @touchmove="handleTouchMove"
		@touchend="handleTouchEnd" @click="handleClick">
		<slot>
			<text class="ball-text">+</text>
		</slot>
	</view>
</template>

<script>
	export default {
		name: "HoverBall",
		props: {
			initPosition: {
				type: Object,
				default: () => ({
					x: 30,
					y: 200
				})
			},
			size: {
				type: Number,
				default: 80
			},
			bgColor: {
				type: String,
				default: "#409eff"
			},
			show: {
				type: Boolean,
				default: true
			}
		},
		data() {
			return {
				ballX: 0,
				ballY: 0,
				startX: 0,
				startY: 0,
				screenWidth: 0,
				screenHeight: 0,
				isDragging: false
			};
		},
		computed: {
			ballStyle() {
				if (!this.show) return {
					display: 'none'
				};
				return {
					left: `${this.ballX}px`,
					top: `${this.ballY}px`,
					width: `${this.size}px`,
					height: `${this.size}px`,
					backgroundColor: this.bgColor
				};
			}
		},
		mounted() {
			const sysInfo = uni.getSystemInfoSync();
			this.screenWidth = sysInfo.windowWidth;
			this.screenHeight = sysInfo.windowHeight;
			this.ballX = this.initPosition.x;
			this.ballY = this.initPosition.y;
			// 从本地恢复位置(可选)
			const savedPos = uni.getStorageSync('hoverBallPos');
			if (savedPos) {
				this.ballX = savedPos.x;
				this.ballY = savedPos.y;
			}
			uni.onWindowResize(() => {
				const sysInfo = uni.getSystemInfoSync();
				this.screenWidth = sysInfo.windowWidth;
				this.screenHeight = sysInfo.windowHeight;
			});
		},
		methods: {
			handleTouchStart(e) {
				this.isDragging = true;
				this.startX = e.touches[0].clientX;
				this.startY = e.touches[0].clientY;
				this.startBallX = this.ballX;
				this.startBallY = this.ballY;
			},
			handleTouchMove(e) {
				if (!this.isDragging) return;
				const dx = e.touches[0].clientX - this.startX;
				const dy = e.touches[0].clientY - this.startY;
				let newX = this.startBallX + dx;
				let newY = this.startBallY + dy;
				newX = Math.max(0, Math.min(newX, this.screenWidth - this.size));
				newY = Math.max(0, Math.min(newY, this.screenHeight - this.size - 100));
				this.ballX = newX;
				this.ballY = newY;
			},
			handleTouchEnd() {
				this.isDragging = false;
				const centerX = this.screenWidth / 2;
				const margin = 10;
				this.ballX = this.ballX < centerX ? margin : this.screenWidth - this.size - margin;
				this.$emit('position-change', {
					x: this.ballX,
					y: this.ballY
				});
			},
			handleClick() {
				console.log('悬浮球打印 - "778899665544112233"')
				if (!this.isDragging) {
					this.$emit('click');
				}
			}
		}
	};
</script>

<style scoped>
	.hover-ball {
	  position: fixed !important; /* 强制fixed定位,不受父元素影响 */
	  border-radius: 50%;
	  display: flex;
	  align-items: center;
	  justify-content: center;
	  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
	  z-index: 9999999 !important; /* 足够高的层级,覆盖所有页面内容 */
	  touch-action: none;
	  transition: left 0.3s ease, top 0.3s ease;
	  pointer-events: auto; /* 确保能点击,不被穿透 */
	}
	
	.ball-text {
	  color: white;
	  font-size: 24px;
	  font-weight: bold;
	}
</style>

二、项目终端 使用npm下载 vue-inset-loader /或/ vite-inset-loader 根据自己项目下载

html 复制代码
npm i vue-inset-loader

npm i Vite-inset-loader

三、在main.js中悬浮组件进行全局注册 示例内容如下

html 复制代码
//导入悬浮球全局注册
import HoverBall from '@/components/HoverBall.vue'

Vue.component("HoverBall",HoverBall); 

四、配置Pages.json

html 复制代码
"uniIdRouter": {},
//在以下写入
"insetLoader": {
		"config": {
			"confirm": "<HoverBall></HoverBall>"
		},
		"label": ["confirm"],
		"rootEle":"view",

        //以下内容可选是否需要
		"package": {
			"label": "view",
			"options": {
				"class": "dev-style",
				"style": {
					"font-size": "24px"
				},
				"data-attr": "content"
			}
		}
	}

重点: 之哟啊关心insetLoader这个对象就行,以上步骤执行后 项目重启还是没有显示组件,注册你显示的悬浮组件是 "div" 还是 "view", 如果是 div: 那么"rootEle":"view"要更改为"rootEle":"div" 很重要!!!。

如果你的代码根元素 有 div 也有 view 请把rootEle设置为 ".*" 👇 。

html 复制代码
"rootEle": ".*"

五、配置vue.config.js / Vite.config.js

html 复制代码
// 解决跨域问题
import {
	defineConfig
} from "vite";
import uni from "@dcloudio/vite-plugin-uni";

//导入统一得基础URL配置
import {
	BASE_API_URL
} from "./common/baseUrl.js";
import {
	UniViteInsetLoader
} from "vite-inset-loader";

const components = {
	PickupDialog: '<PickupDialog ref="PickupDialogRef" />',
	confirm: '<HoverBall></HoverBall>'
};

export default defineConfig({
	plugins: [UniViteInsetLoader({
		include: "pages"
	}), uni()],
	server: {
		proxy: {
			"/api": {
				// 代理路径
				target: BASE_API_URL,
				changeOrigin: true, // 是否换源
				rewrite: (path) => path.replace(/^\/api/, ""), // 重写路径
			},
		},
	},
});

完成以上步骤 记得重启项目!!! 否则不会生效!!!

相关推荐
子兮曰6 小时前
Bun v1.3.14 深度解析:Image API、HTTP/3、全局虚拟存储与五十项变革
前端·后端·bun
kyriewen7 小时前
今天,百年巨头一次砍了9200人,而一个离职科学家的实话让全网睡不着觉
前端·openai·ai编程
问心无愧05137 小时前
ctf show web 入门42
android·前端·android studio
kyriewen7 小时前
老板逼我上AI,我偷偷在浏览器里跑LLaMA,省下20万API费
前端·react.js·llm
Beginner x_u8 小时前
前端八股整理(手写 02)|数组转树、数组扁平化、随机打乱一个数组
前端·数组·数组转树·数组扁平化
KaMeidebaby8 小时前
卡梅德生物技术快报|禽类成纤维细胞 FISH 实验:鸟类性别染色体基因定位技术实现与数据验证
前端·数据库·其他·百度·新浪微博
天若有情6738 小时前
前端高阶性能优化:跳出传统懒加载与预加载,基于用户行为做轻量预判加载
前端·性能优化
小小小小宇8 小时前
前端转后端:SQL 是什么
前端
张元清9 小时前
React Observer Hooks:7 种监听 DOM 而不写样板代码的方式
前端·javascript·面试
广州华水科技9 小时前
单北斗GNSS变形监测是什么?主要有怎样的应用与优势?
前端