mirror of
http://112.124.100.131/GFRS/ebiz-h5.git
synced 2025-12-09 15:46:43 +08:00
feat(ebiz): 优化FAB组件拖拽功能
- 修复当移动浮窗之后,点击其他地方浮窗会出现点击位置的问题 - 完善拖拽相关数据字段注释 - 新增窗口大小更新方法 - 重构拖拽开始、进行和结束逻辑 - 添加触摸事件支持和边界限制 - 实现点击与拖拽事件的正确分离
This commit is contained in:
@@ -30,18 +30,20 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
isDragging: false,
|
||||
hasDragged: false, // 新增:标记是否发生了拖拽
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
posX: 0,
|
||||
posY: 0,
|
||||
windowWidth: 0,
|
||||
windowHeight: 0,
|
||||
fabWidth: 0,
|
||||
fabHeight: 0,
|
||||
initialX: 0,
|
||||
initialY: 0
|
||||
isDragging: false, // 是否正在拖动
|
||||
hasDragged: false, // 是否发生了拖拽
|
||||
startX: 0, // 触摸点相对于元素左上角的X偏移
|
||||
startY: 0, // 触摸点相对于元素左上角的Y偏移
|
||||
posX: 0, // 元素当前位置X
|
||||
posY: 0, // 元素当前位置Y
|
||||
initialTouchX: 0, // 初始触摸点X
|
||||
initialTouchY: 0, // 初始触摸点Y
|
||||
windowWidth: 0, // 视口宽度
|
||||
windowHeight: 0, // 视口高度
|
||||
fabWidth: 0, // FAB宽度
|
||||
fabHeight: 0, // FAB高度
|
||||
initialX: 0, // 初始位置X
|
||||
initialY: 0 // 初始位置Y
|
||||
}
|
||||
},
|
||||
|
||||
@@ -79,6 +81,9 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 更新窗口大小
|
||||
*/
|
||||
updateWindowSize() {
|
||||
this.windowWidth = window.innerWidth
|
||||
this.windowHeight = window.innerHeight
|
||||
@@ -90,89 +95,128 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 开始拖动
|
||||
* @param event {TouchEvent}
|
||||
*/
|
||||
startDrag(event) {
|
||||
if (!this.draggable) return
|
||||
|
||||
// 阻止默认行为(如页面滚动)和事件冒泡
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const touch = event.touches[0]
|
||||
|
||||
// 记录初始触摸位置
|
||||
this.initialTouchX = touch.clientX
|
||||
this.initialTouchY = touch.clientY
|
||||
|
||||
// 记录元素当前位置和触摸点的偏移
|
||||
this.startX = touch.clientX - this.posX
|
||||
this.startY = touch.clientY - this.posY
|
||||
|
||||
// 设置拖动状态
|
||||
this.isDragging = true
|
||||
this.hasDragged = false
|
||||
|
||||
const clientX = event.touches ? event.touches[0].clientX : event.clientX
|
||||
const clientY = event.touches ? event.touches[0].clientY : event.clientY
|
||||
|
||||
this.startX = clientX - this.posX
|
||||
this.startY = clientY - this.posY
|
||||
|
||||
// 禁用文本选择
|
||||
document.body.style.userSelect = 'none'
|
||||
|
||||
const options = { passive: false }
|
||||
document.addEventListener('mousemove', this.onDrag, options)
|
||||
document.addEventListener('touchmove', this.onDrag, options)
|
||||
document.addEventListener('mouseup', this.stopDrag, options)
|
||||
document.addEventListener('touchend', this.stopDrag, options)
|
||||
document.body.style.webkitUserSelect = 'none'
|
||||
},
|
||||
|
||||
/**
|
||||
* 拖动中
|
||||
* @param event { TouchEvent }
|
||||
*/
|
||||
onDrag(event) {
|
||||
if (!this.isDragging) return
|
||||
|
||||
this.hasDragged = true
|
||||
// 阻止默认行为(如页面滚动)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const clientX = event.touches ? event.touches[0].clientX : event.clientX
|
||||
const clientY = event.touches ? event.touches[0].clientY : event.clientY
|
||||
// 获取当前触摸点
|
||||
const touch = event.touches[0]
|
||||
|
||||
let newX = clientX - this.startX
|
||||
let newY = clientY - this.startY
|
||||
// 计算新位置(相对于初始触摸点的偏移)
|
||||
let newX = touch.clientX - this.startX
|
||||
let newY = touch.clientY - this.startY
|
||||
|
||||
// 应用边界限制
|
||||
if (this.boundary) {
|
||||
newX = Math.max(0, Math.min(newX, this.windowWidth - this.fabWidth))
|
||||
newY = Math.max(0, Math.min(newY, this.windowHeight - this.fabHeight))
|
||||
const maxX = this.windowWidth - this.fabWidth
|
||||
const maxY = this.windowHeight - this.fabHeight
|
||||
|
||||
// 确保不会移出视口
|
||||
newX = Math.max(0, Math.min(newX, maxX))
|
||||
newY = Math.max(0, Math.min(newY, maxY))
|
||||
}
|
||||
|
||||
// 使用transform实现平滑移动
|
||||
this.posX = newX
|
||||
this.posY = newY
|
||||
|
||||
// 标记为已拖动,防止点击事件触发
|
||||
if (Math.abs(touch.clientX - this.initialTouchX) > 5 || Math.abs(touch.clientY - this.initialTouchY) > 5) {
|
||||
this.hasDragged = true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 拖动结束
|
||||
* @param event { TouchEvent }
|
||||
*/
|
||||
stopDrag(event) {
|
||||
if (!this.isDragging) return
|
||||
|
||||
this.isDragging = false
|
||||
document.body.style.userSelect = ''
|
||||
this.removeEventListeners()
|
||||
|
||||
// 如果是拖拽结束,阻止后续的点击事件
|
||||
if (this.hasDragged) {
|
||||
// 延迟重置标志位,确保不会触发点击事件
|
||||
setTimeout(() => {
|
||||
this.hasDragged = false
|
||||
}, 100)
|
||||
// 阻止事件冒泡,避免触发父元素的点击事件
|
||||
if (event) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
this.removeEventListeners()
|
||||
this.$emit('drag-end', { x: this.posX, y: this.posY })
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击事件
|
||||
* @param event { TouchEvent }
|
||||
*/
|
||||
handleClick(event) {
|
||||
// 如果是拖拽操作,不触发点击事件
|
||||
if (this.isDragging || this.hasDragged) {
|
||||
if (this.hasDragged) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
this.hasDragged = false
|
||||
return
|
||||
return false
|
||||
}
|
||||
this.$emit('click', event)
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* 移除事件监听器
|
||||
*/
|
||||
removeEventListeners() {
|
||||
const options = { passive: false }
|
||||
document.removeEventListener('mousemove', this.onDrag, options)
|
||||
document.removeEventListener('touchmove', this.onDrag, options)
|
||||
document.removeEventListener('mouseup', this.stopDrag, options)
|
||||
document.removeEventListener('touchend', this.stopDrag, options)
|
||||
// 恢复用户选择
|
||||
document.body.style.userSelect = ''
|
||||
document.body.style.webkitUserSelect = ''
|
||||
|
||||
// 重置拖动状态
|
||||
this.isDragging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="fab" :style="fabStyle" class="fab-container" @mousedown="startDrag" @touchstart="startDrag">
|
||||
<div class="fab-content" @click="handleClick" @touchend="handleClick">
|
||||
<div ref="fab" :style="fabStyle" class="fab-container" @touchend="handleClick" @touchmove="onDrag" @touchstart="startDrag">
|
||||
<div class="fab-content">
|
||||
<slot>
|
||||
<div class="fab-default">
|
||||
<i v-if="icon" :class="icon"></i>
|
||||
@@ -188,9 +232,10 @@ $base: #e9332e;
|
||||
|
||||
.fab-container {
|
||||
position: fixed;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
touch-action: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.fab-content {
|
||||
|
||||
Reference in New Issue
Block a user