一、创建一个悬浮组件,代码示例如下,根据自己情况而定。
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/, ""), // 重写路径
},
},
},
});
完成以上步骤 记得重启项目!!! 否则不会生效!!!