右下角悬浮随意拖动banner组件封装

本文介绍右下角悬浮随意拖动banner组件的封装。先讲解MouseEvent相关知识及H5无法触发该事件的解决办法,接着阐述实现思路,包括初始化位置、拖动时动态改变位置及保存最新位置,还提及开发中遇到的问题及解决方案,最后给出源码和使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

右下角悬浮随意拖动banner组件封装

前言

在参加掘金1024活动时,注意到页面右下角的悬浮的banner,这种表现效果优于直接悬浮位置固定不变的方式,因为它可以随意拖动并改变位置。在以前的H5开发中,也遇到了类似的效果。因此决定将它抽离为一个单独的组件,防止以后重复搬砖。直接访问获取源码:https://gitee.com/fcli/vue_drag.git

先了解下相关知识

MouseEvent

当我们进行鼠标操作,比如mousedown、mousemove、mouseup时,能得到一个返回参数,从参数中我们能够得到鼠标相关数据信息。在这我简单对几个常用的参数进行介绍:

1、clientX、clientY:返回触发鼠标事件时,鼠标指针相对于当前窗口的水平和垂直坐标

2、offsetX、offsetY:返回鼠标指针相对于目标元素边缘位置的水平和垂直坐标。

3、pageX、pageY:回触发鼠标事件时鼠标指针相对于文档的水平和垂直坐标。

H5无法触发MouseEvent问题

1、当我们在移动端H5操作时,页面点击、拖动,无法触发mouse相关事件,此时我们需要通过TouchEvent来进行替换捕获相关事件,比如touchstart对应mousedown。

实现思路

1、首先需要初始化悬浮位置,需要设置fixed布局,以保证设置的位置是相对于浏览器窗口,不受其他样式影响。

.drag-content {
    user-select: none;
    touch-action: none;
    cursor: pointer;
    position: fixed;
}

2、在拖动时通过监听鼠标按下后位置的变化,动态改变悬浮Dom的位置,此处可使用两种方案:
(1)动态改变Dom距离浏览器left和bottom的位置
(2)使用transform改变dom的位置
我采用第二中方式,这样性能上更好一点。

3、保存最新位置,再下次刷新页面或者重新拖动时能够从上一次拖拽的位置重新计算移动距离。

//拖动中,动态改变
const moveTouch = (e: any) => {
    if (isDragging) {
        //h5 touch事件
        let offsetX = e.touches[0].pageX - dragInfo.offsetX;
        let offsetY = e.touches[0].pageY - dragInfo.offsetY;

        //保存最新便宜量
        dragInfo.endX = offsetX;
        dragInfo.endY = offsetY;
        dragStyle.value.transform = `translate(${offsetX}px,${offsetY}px)`
    }
}

遇到的问题

在开发组件时候遇到一个问题,如果我将mousemove事件直接绑定在拖动的Dom上时会出现鼠标滑动太快导致拖拽物脱离鼠标,或者拖拽卡顿。解决方案:将mousemove事件挂在docment,而不是对应的element,此时鼠标滑动只要不出docment范围就不会触发上述情况。

源码


<template>
    <div class="drag-content" :style="dragStyle" @mousedown="startTouch" @touchstart="startTouch"
        @touchend="endTouch" @mouseup="endTouch" @touchmove="moveTouch">
        <slot></slot>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
const props = defineProps({
    right: {
        type: String,
        default: "20px"
    },
    bottom: {
        type: String,
        default: "30px"
    }
})

//拖动样式
const dragStyle = ref({
    right: props.right,
    bottom: props.bottom,
    transform: 'translate(0,0)'
})
let isDragging = false;
let dragInfo = {
    offsetX: 0,
    offsetY: 0,
    endX: 0,
    endY: 0
}

//拖拽开始
const startTouch = (e: any) => {
    dragInfo.offsetX = (e.pageX || e.touches[0].pageX) - dragInfo.endX;
    dragInfo.offsetY = (e.pageY || e.touches[0].pageY) - dragInfo.endY;
    isDragging = true;
}

//适配pc端鼠标移动事件卡顿问题
document.onmousemove =  (e)=> {
    if (isDragging) {
        let offsetX = e.pageX - dragInfo.offsetX;
        let offsetY = e.pageY - dragInfo.offsetY;
        dragInfo.endX = offsetX;
        dragInfo.endY = offsetY;
        dragStyle.value.transform = `translate(${offsetX}px,${offsetY}px)`
    }
}

//拖动中,动态改变
const moveTouch = (e: any) => {
    if (isDragging) {
        //h5 touch事件
        let offsetX = e.touches[0].pageX - dragInfo.offsetX;
        let offsetY = e.touches[0].pageY - dragInfo.offsetY;

        //保存最新便宜量
        dragInfo.endX = offsetX;
        dragInfo.endY = offsetY;
        dragStyle.value.transform = `translate(${offsetX}px,${offsetY}px)`
    }
}

//结束拖动
const endTouch = () => {
    isDragging = false;
}

</script>
<style>
.drag-content {
    user-select: none;
    touch-action: none;
    cursor: pointer;
    position: fixed;
}
</style>

使用示例

npm install @fcli/vue-drag --save-dev 来安装

在项目中使用
import VerCode from '@fcli/vue-vercode';
const app=createApp(App)
app.use(VerCode);

 <div class="content">
    <vue-drag right="20px" bottom="30px">
      <div class="circle">+</div>
    </vue-drag>
</div>
参数说明
属性属性名称类型可选值
right初始化时距离右边的距离string20px
bottom初始化时距离底部的距离string30px
slot

可拖拽组件中的自定义内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落风尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值