快捷实现dom拖拽

1,291 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

前言

大家好,我是小阵 🔥,一路奔波不停的码字业务员
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~😋
加我微信:zzz886885,邀你进群,一起学习交流,摸鱼学习两不误🌟

开开心心学技术大法~~

开心

来了来了,他真的来了~

正文

先看效果

iShot_2022-08-10_21.26.06

实现思路

  • 刚看到这个的第一个想法是什么?

  • 是否是:

    • mousedown的时候拿到该元素本身于该元素的位置信息,然后根据鼠标移动同步控制移动该dom
    • 同时监听mouseover事件,跟任意一个其他dom的位置信息比较,如果在位置信息内且该dom可以承载下移动dom,也就是宽高要大于可移动dom,如果满足条件的话给可承载移动dom的容器dom添加一些样式,让我们一眼可以看出该移动dom可以被放置到该容器dom
    • 之后监听mosedown事件,看是否鼠标位置在容器dom
  • 以上思路当然也可以解决,但是有更好的方案可以实现这些效果

  • 这就用到了dragstartdragenddragenterdragleavedrop等事件

    image-20220810210333770

    可以看到这一系列的事件兼容性还是可以的。

  • 当然dragestart一系列事件还需要跟domdraggable='true'属性一起使用

    • 顾名思义,dom上添加draggable='true'表示可以被拖拽,默认是auto
  • 依据以上思路,我们需要:

    • 移动dom触发dragstart的时候,给该dom添加一些拖拽样式

      • 注意,试想一下,我们拖拽前和拖拽后给被拖拽dom添加样式时有什么不一样

      • 我们知道,对于一般dom来说,添加的所有样式都会按照预期生效,拖拽前的dom就是这种状态。

      • 但是拖拽后的dom会在原来的位置上保留原dom,然后在拖拽的dom其实是一个副本dom。我们要做的其实就是两点

        1. 拖拽时隐藏掉原dom
        2. 拖拽的同时给副本dom一个样式
      • 要实现以上效果,需要同步异步一起用,同步的给原本dom与副本dom添加一个拖拽样式,然后异步给一个隐藏原本dom的样式。

      • 因为在拖拽前原dom已经同步更改成了拖拽样式,所以被拖拽dom也就有了拖拽样式

      • 又因为异步将原dom隐藏的时候,被拖拽dom已经被拖拽了,所以原dom的隐藏样式就没办法在被拖拽dom上生效了。

      • 这也就达成了我们的目的

  • 之后简单了,触发dragenter的dom就是被拖拽元素进入到可放置元素的时候,这时可以更改下可放置元素的样式

    • 这里有可放置元素的概念,这个其实就是比大小,可放置元素一定要比拖拽元素大,也就是之前提到过的内容
  • drageleave触发时同理

  • drop触发时将被拖拽dom塞入到该可放置元素中即可

    • 那还用删除掉原dom吗?不用的,因为这就是dragEvent的又一个方便之处呀

具体实现

基础html

<div class="empty">
  <div class="fill" draggable="true"></div>
</div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>

设置几个dom容器,设置一个填充img的元素用作拖拽元素

实现基础样式

.empty {
  height: 150px;
  width: 150px;
  margin: 10px;
  border: solid 3px black;
  background: white;
}
.empty-small {
  height: 50px;
  width: 50px;
  margin: 10px;
  border: solid 3px black;
  background: white;
}
​
.fill {
  background-image: url('https://images.unsplash.com/photo-1658786335140-e42b16e8f462?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=150&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY2MDEzNjk3NQ&ixlib=rb-1.2.1&q=80&w=150');
  height: 145px;
  width: 145px;
  cursor: pointer;
}
​
.hold {
  border: solid 5px #ccc;
}
​
.hovered {
  background-color: #333;
  border-color: white;
  border-style: dashed;
}

这个基本都是静态css

添加拖拽事件

const fill = document.querySelector('.fill')
const empties = document.querySelectorAll('.empty')
​
fill.addEventListener('dragstart', dragStart)
fill.addEventListener('dragend', dragEnd)
​
for (const empty of empties) {
    empty.addEventListener('dragover', dragOver)
    empty.addEventListener('dragenter', dragEnter)
    empty.addEventListener('dragleave', dragLeave)
    empty.addEventListener('drop', dragDrop)
}
​
function dragStart() {
    this.className += ' hold'
    setTimeout(() => this.className = 'invisible', 0)
}
​
function dragEnd() {
    this.className = 'fill'
}
​
function dragOver(e) {
    console.log('dragOver')
    e.preventDefault()
}
​
function dragEnter(e) {
    console.log('dragEnter')
    e.preventDefault()
    this.className += ' hovered'
}
​
function dragLeave() {
    console.log('dragEnter')
    this.className = 'empty'
}
​
function dragDrop() {
    this.className = 'empty'
    this.append(fill)
}

关键是dragEvent的使用

注意,dragOver中一定要设置e.preventDefault(),否则drag事件触发后会触发dragOver事件导致append失败

完整代码

总结

  • 关键dragEvent事件的使用
  • 还有一点就是对拖拽元素施加拖拽样式时的细节处理

结语

如果文章真的有帮到你,希望可以多多点赞、收藏、关注支持一波呀!!小阵会很开心哒~

热爱开源,支持开源,拥抱开源!

文章如有错误或不严谨之处,还望指出,感谢感谢!!!

加油!

往期好文推荐「我不推荐下,大家可能就错过了史上最牛逼vscode插件集合啦!!!(嘎嘎~)😄」