满足大屏场景的拖拽组件原理说明

✍️ 源于大屏场景下,由于进行适配页面尺寸,随着页面尺寸的频繁变化,导致拖拽组件的定位失效,引起拖拽异常......
场景🦄
组件需要满足功能:
- 基本PC端拖拽功能;
- 适配屏幕尺寸变化;
- 支持传入组件的定位
top, left
;(防止突发性页面尺寸比例变化,拖拽组件定位失效)
拖拽原理
所需事件
- onMousedown
- onMouseup
- onMousemove
原理说明
原理图🍥

状态参数
const dragData =
{
// x偏移值
offsetX: 0,
// y偏移值
offsetY: 0,
// 是否开始拖拽
isDrag: false,
// 当前组件距离当前窗口x轴的距离
distanceX: 0,
// 当前组件距离当前窗口y轴的距离
distanceY: 0,
// 组件top定位
top: 0,
// 组件left定位
left: 0,
}
步骤
第一步
鼠标移动到组件可触发区域,鼠标按下,触发onMousedown
事件,记录鼠标点击位置,开启拖动
// 记录鼠标点击位置
dragData.distanceX = e.clientX
dragData.distanceY = e.clientY
// 开启拖动
dragData.isDrag = true
第二步
鼠标移动,触发onMousemove
事件,判断dragData.isDrag
是否为真,为假跳出执行,为真继续执行。通过计算移动的距离,获取当前组件位置,算出最新位置,对组件进行更新位置信息。并记录当前组件距离当前窗口的距离、此时的偏移位置;
计算移动的距离:
计算移动的距离 = 本次距离当前窗口移动距离 - 上次距离当前窗口移动距离 + 上一次移动距离
const moveDistanceX = e.clientX - distanceX + offsetX
const moveDistanceY = e.clientY - distanceY + offsetY
获取最新位置:
不带页面缩放:
最新位置 = 当前组件的位置 + 移动的距离
带页面缩放:
最新位置 = 当前组件的位置 + 移动的距离/页面缩放系数
const _left = left + moveDistanceX / scaleX
const _top = top + moveDistanceY / scaleY
更新组件位置信息:
el.style.left = _left + 'px'
el.style.top = _top + 'px'
记录状态:
记录当前组件距离当前窗口的距离:
dragData.distanceX = e.clientX
dragData.distanceY = e.clientY
记录当前偏移位置
dragData.offsetX = moveDistanceX
dragData.offsetY = moveDistanceY
第三步
鼠标抬起,触发onMouseup
事件,关闭拖动;
dragData.isDrag = false
适配屏幕尺寸变化
场景
用户控制屏幕,使屏幕尺寸发送变化,使拖拽组件保存的定位信息过期,导致拖拽异常。
所需事件
- onResize
原理说明
向window
绑定resize
事件,监控页面尺寸变化,当尺寸发生变化,或者最新组件定位,清空保存的定位状态信息。
const { left, top } = el.style
const _top = +top.replace(/px/, '')
const _left = +left.replace(/px/, '')
dragData = {
offsetX: 0,
offsetY: 0,
isDrag: false,
distanceX: 0,
distanceY: 0,
top: _top,
left: _left,
}
突发性页面尺寸比例变化定位修复
场景
没有通过resize
事件触发的页面尺寸变化,通过修改页面宽高等导致页面尺寸变化,这时组件定位不准,需要恢复同比例下组件定位,并保证组件拖拽无异常。
条件
页面原始宽高,变化后页面宽高
方案
根据页面比例,计算出最新组件位置,对组件进行更新位置信息,并清空保存的定位状态信息。
页面比例 = 页面原始宽高 / 变化后页面宽高
最新组件位置 = 当前组件位置 / 页面比例