Skip to content

这次是一次需求引起的反思。现在 MVVM 框架越来越流行,并且大多数都已经实现了双向绑定,使得人们无需考虑如何去获取 DOM 元素,给他们增加样式,实现各种各样的动画等等。很多动画库都实现了绚丽的效果并且无需来考虑兼容性。但是 JS 变得越来越便利的时候,我们好像忘记了一些基本技能,比如如何用原生实现各种动画,以及拖拽。

这次我们的需求是需要实现一个卡列表拖拽转账的功能。卡列表数量不定,高度不定。具体交互是 鼠标长按某一张卡,然后拖到另一张卡上面去进行转账。中间不能有卡顿,并且卡列表太长时,卡片滑到底部或顶部,能够自动触发滚动事件。所以具体要实现以下几点:

  • 要识别拖动元素和滚动屏幕两种效果,具体是用户长按某一张卡就可以拖动,否则就是直接滚动屏幕。
  • 长按拖动实际是复制该元素的一个副本,副本完成拖动效果,实际的元素位置不变。
  • 拖动的时候要识别是否接近顶部或者底部,这个时候就要触发滚动条来使屏幕滚动。
  • 识别拖动的目标位置,当拖动完成时能获取拖动结束时目标元素的信息。

刚开始时找了好久的源码、插件什么的,但是都不是很满意,因为有些插件定制的功能不用不到,改动的话又需要花费大量时间。所以接下来的话还是自己手动实现把!

前期做了一些准备工作(其实就是踩那些插件的坑),定了下面的方案,首先不能用 H5 的Drag事件 和 mouse,因为它不支持移动端,Drag 是H5的新特性 在低版本浏览器的兼容性也不好,所以,综合考虑 采用了 touch 系列的事件。

代码是次要的,主要是来说说思路。

识别长按和拖动

这个主要是通过给元素设置定位来实现的。我们知道移动端touch有三个事件 touchstart``touchmove touchend 如果是长按会把拖拽元素的定位设置成absolute 根据计算的定位可以来进行拖动,如果元素的position:reletive,则只会触发滚动条。具体的实现方法是在 touchstart 事件中 加个 setTimeout

js
//部分代码
ele.addEventListener('touchstart',()=>{
    if(this.style.position !== 'absolute'){
       longTouch =  setTimeout(()=>{
            this.style.position = 'absolute';
        },500)
    }
})

ele.addEventListener('touchmove',()=>{
    clearTimeout(longTouch)
})