要先引入 “vue3-draggable-resizable”: “^1.6.5”
1.创建DragComponent组件
<template><!-- 抽屉组件 --><div class="drag-container" id="dragBox" :style="{ zIndex: zIndex }"><Vue3DraggableResizable :initW="64" :initH="64" v-model:x="x" v-model:y="y":parent="false" :resizable="false" :draggable="true" class="drag-item" @drag-start="handleDragStart"@drag-end="handleDragEnd"><div class="home-icon-box" ref="draggableElement"><img :src="market_set.image" class="img" alt="" /></div></Vue3DraggableResizable></div>
</template><script setup>import {ref,onMounted,onUnmounted} from 'vue';import Vue3DraggableResizable from 'vue3-draggable-resizable';import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';import {getMarket} from "@/api/global.js"const popupRef = ref(null)const x = ref(20);const y = ref();const initialY = ref(0); // 基准Y坐标,用于计算滚动偏移const isDragging = ref(false); //是否正在拖拽const dragStartPosition = ref({x: 0,y: 0}); // 拖拽起始位置const isLock = ref(true);const isShow = ref(false)// 初始化基准Y坐标const initBaseY = () => {initialY.value = y.value - window.scrollY;};function isElementInViewport(el) {const rect = el.getBoundingClientRect();// 获取视口的高度和宽度const windowHeight = (window.innerHeight || document.documentElement.clientHeight) - 50;const windowWidth = (window.innerWidth || document.documentElement.clientWidth);// 判断元素是否在视口内const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);return (vertInView && horInView);}// 拖动结束后更新基准Y坐标const handleDragEnd = (e) => {// initialY.value = y.value - window.scrollY;// 判断拖拽还是点击事件if (isDragging.value) {const dragDistance = Math.sqrt(Math.pow(e.x - dragStartPosition.value.x, 2) +Math.pow(e.y - dragStartPosition.value.y, 2));if (dragDistance < 5) {// 如果拖拽距离小于 5px,则认为是点击事件console.log('点击事件', e);isLock.value = true} else {console.log('拖拽结束', e);isLock.value = false}}isDragging.value = false;// 判断悬浮球是靠近左边或右边const {x: newX,y: newY} = e; // 假设位置属性是 x 和 const page = document.querySelector('#app');const iconBox = document.querySelector('.home-icon-box');// alert(page.offsetWidth)if (newX + (iconBox.offsetWidth / 2) < page.offsetWidth / 2) {x.value = 0; // 靠左} else {x.value = page.offsetWidth - 64; // 靠右}const myElement = document.querySelector('.home-icon-box');if (isElementInViewport(myElement)) {console.log('元素在视口内');} else {console.log('元素不在视口内');y.value = window.innerHeight / 2}};const handleDragStart = (e) => {// 可根据需要添加拖动开始时的逻辑isDragging.value = true;dragStartPosition.value = {x: e.x,y: e.y};};// 计算按钮初始y位置const containerWidth = ref(0); // 容器宽度const width = ref(100); // 组件宽度// 计算初始 x 坐标(从右对齐)const calculateInitialX = () => {x.value = containerWidth.value - width.value;y.value = (window.innerHeight || document.documentElement.clientHeight) - 200};// 生命周期onMounted(() => {initBaseY();const container = document.querySelector('#app');if (container) {containerWidth.value = container.offsetWidth; //活动区域的宽度范围calculateInitialX();}})
</script><style lang="scss" scoped>.dragBox {width: 960rpx;height: 100vh;position: fixed;top: 0;left: 50%;z-index: 99;transform: translateX(-50%);pointer-events: none;color: red;}.home-icon-box {position: relative;// left: 23px;// top: 23px;width: 128rpx;height: 128rpx;display: flex;justify-content: center;align-items: center;z-index: 999;color: #fff;cursor: grab;/* 鼠标样式为抓取 */user-select: none;/* 防止拖拽时选中文本 */animation: pulse 1.5s infinite ease-in-out;transition: opacity 0.3s ease, left 0.3s ease, right 0.3s ease, top 0.3s ease;/* 按钮动画 */@keyframes pulse {0% {transform: scale(1);opacity: 1;}50% {transform: scale(1.2);opacity: 0.7;}100% {transform: scale(1);opacity: 1;}}/* 进度条容器 */.progress-container-icon {position: absolute;width: 80%;height: 10px;background: rgba(255, 255, 255, 0.5);border-radius: 5px;overflow: hidden;text-align: center;cursor: pointer;bottom: -14px;}/* 进度条 */.progress-bar-icon {width: 0%;height: 100%;background: #ff5722;border-radius: 5px;}/* 进度文本 */.progress-text-icon {position: absolute;width: 100%;text-align: center;top: 50%;transform: translateY(-50%);color: black;font-size: 10px;font-weight: bold;}.img {width: 100%;height: 100%;}}.drag-item {width: 64px;height: 64px !important;touch-action: none;border: none !important;}.drag-container {display: inline-block;position: fixed;top: 0;z-index: 99;}.dragBoxPopup {position: fixed;top: 0;left: calc(50% - min(50%, 240px));width: min(100%, 480px);z-index: 999;height: 100%;background-color: rgba(0, 0, 0, 0.7);}}
</style>
2.createDrag.js 将组件dom创建到app根组件下
import { createVNode, render } from 'vue';
import DragComponent from '@/components/DragComponent/DragComponent.vue';// 修改后的函数,负责渲染 DragComponent 和 DragComponent2
export default function createDrags() {// 创建一个组件的 DOM 容器const container1 = document.createElement('div');document.getElementById('app').appendChild(container1);// 创建一个组件的虚拟节点const vnode1 = createVNode(DragComponent, {// 如果需要,可以在这里传递其他 props 给 DragComponent});// 渲染一个组件render(vnode1, container1);const instance1 = vnode1.component?.proxy;// 返回两个组件的实例(如果需要后续操作)return {dragComponentInstance: instance1};
}
在App.vue中执行js
import createDrag from "@/utils/createDrag.js"onLaunch: function(options) {createDrag()}