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/, ""), // 重写路径
			},
		},
	},
});

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

相关推荐
allenjiao2 小时前
WebGPU vs WebGL:WebGPU什么时候能完全替代WebGL?Web 图形渲染的迭代与未来
前端·图形渲染·webgl·threejs·cesium·webgpu·babylonjs
上车函予2 小时前
geojson-3d-renderer:从原理到实践,打造高性能3D地理可视化库
前端·vue.js·three.js
孟祥_成都2 小时前
别被营销号误导了!你以为真的 Bun 和 Deno 比 Node.js 快很多吗?
前端·node.js
Lsx_2 小时前
🔥Vite+ElementPlus 自动按需加载与主题定制原理全解析
前端·javascript·element
零一科技2 小时前
Vue3拓展:实现原理 - 浅析
前端·vue.js
抱琴_2 小时前
【Vue3】从混乱到有序:我用 1 个 Vue Hooks 搞定大屏项目所有定时任务
前端·vue.js
文心快码BaiduComate3 小时前
用文心快码写个「隐私优先」的本地会议助手
前端·后端·程序员
Cerrda3 小时前
Windows系统中使用fnm自动管理node版本
前端
胡琦博客3 小时前
21天开源鸿蒙训练营|Day2 ReactNative 开发 OpenHarmony 应用环境搭建实录
javascript·react native·react.js