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

✍️ 源于大屏场景下,由于进行适配页面尺寸,随着页面尺寸的频繁变化,导致拖拽组件的定位失效,引起拖拽异常......

场景🦄

组件需要满足功能:

  • 基本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事件触发的页面尺寸变化,通过修改页面宽高等导致页面尺寸变化,这时组件定位不准,需要恢复同比例下组件定位,并保证组件拖拽无异常。

条件

页面原始宽高,变化后页面宽高

方案

根据页面比例,计算出最新组件位置,对组件进行更新位置信息,并清空保存的定位状态信息。

页面比例 = 页面原始宽高 / 变化后页面宽高

最新组件位置 = 当前组件位置 / 页面比例