前言
这次在chrome插件的开发过程中有需求要实现一个拖拽的功能,所以这次来介绍一下网页中的拖拽。在网页中我们经常能见到拖拽功能,大致可以分为两种,一种是通过拖拽来改变dom元素的位置,还有一种则一般是通过拖拽来上传文件,这两种拖拽各有各的应用常见,但是使用的技术还是有挺大的差别的,这篇文章就来介绍一下这两种拖拽方式以及二者之间的区别。
第一种:改变元素的位置
这种拖拽的实现思路是通过鼠标的按下与抬起的事件来判断拖拽开始与拖拽结束,而通过鼠标的移动事件来修改元素的位置,从而实现拖拽的效果,思路比较简单,来看看究竟是怎么样实现的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44<style>
  .box1 {
    width: 200px;
    height: 200px;
    background-color: bisque;
    position: absolute;
    top: 40px;
    left: 100px;
  }
</style>
<body>
  <div class="box1"></div>
  <script src="./js/jquery-3.4.1.min.js"></script>
  <script>
    $(function () {
      const box1 = $('.box1');
      // 定义一个变量来判断是否正在拖拽
      let isDraging = false;
      let x, y;
      box1.mousedown(function (e) {
        e = e || window.event;
        // 这里的diffX和diffY实际上指的就是元素中心点到边框的距离
        diffX = e.clientX - box1.offset().left;
        diffY = e.clientY - box1.offset().top;
        isDraging = true;
      })
      // 将事件绑定在document上防止拖动太快导致反应不过
      $(document).mousemove(function (e) {
        if (isDraging) {
          e = e || window.event;
          // 这里新的坐标指的是中心的位置减去中心到边框的距离。
          // 因为绝对定位的top和left算的是边框到父级定位元素的距离
          let newX = e.clientX - diffX;
          let newY = e.clientY - diffY;
          box1.css({ 'top': newY + 'px', 'left': newX + 'px' })
        }
      })
      // 同样防止过快触发错误
      $(document).mouseup(function () {
        isDraging = false;
      })
    })
  </script>
</body>
需要注意的地方已经在代码中注释出来了,这里是通过绝对定位的方式来进行修改的,因为需要脱离文档流。
这里是通过jQuery来实现的,只是演示一下原理,貌似通过原生JS来实现还会方便一点。
第二种:HTML拖拽
这种方式的拖拽主要是要用到HTML提供的API,因为HTML本身就是支持拖拽上传文件的,但是除了特定的一些文件或者是链接之类的可以拖动之外,其他的元素想要拖动就必须设置其 draggable :<element draggable="true | false | auto" >
设置为 true 之后就可以随意进行拖动了,但是要注意的是这里的拖动还是和上面提到的第一种的拖动方式是有很大的区别的,这种拖动方式只能拖动到另一个元素中,而不像是第一种方式没有限制。 dragenter 和 dragover 事件的默认行为是拒绝接受任何被拖放的元素,所以要想拖入目的地元素也还必须要先阻止其默认行为,否则也是拖不进去的。
最简单的拖拽例子:
1  | <style>  | 
这样就实现了最简单的拖拽,可以将一个元素拖拽到另一个元素中。
当然这是最简单的拖拽,完整的拖拽过程应该包括:
被拖拽元素的 dragstart(开始拖拽时触发) 、drag(拖拽过程中反复触发) 、dragend(在拖动操作完成时触发)
拖拽目的地的 dragenter(进入拖拽目的地触发) 、 dragover(在拖拽目的地内触发) 、dragleave(离开拖拽目的地触发) 以及 drop(在目的地内放下触发) 事件
这些事件就组成了一个完整的拖拽过程。可以根据这些事件来自定义拖拽时的表现。
dataTransfer
如果需要在拖拽的过程中进行拖拽元素与目的地元素的数据交互就可以通过 dataTransfer 的 setData() 方法设置被拖数据的数据类型和值,然后通过 getData
方法来获取相应的值。
还可以通过 dataTransfer 中的 files 属性来获取上传的文件列表从而实现拖拽上传的功能:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29<style>
  .box2 {
    width: 300px;
    height: 300px;
    margin-top: 40px;
    background-color: aquamarine;
  }
</style>
<body>
  <div class="box2"></div>
  <img src="" alt="" class="pre">
  <script>
    const box2 = document.querySelector('.box2');
    box2.ondrop = function (e) {
      e = e || window.event;
      e.preventDefault();
      // 这里要注意的一件事情是直接看 dataTransfer 中的fileList是看不到任何的文件信息的,只有看 dataTransfer.files 才能看到文件信息
      console.log(e.dataTransfer.files[0]);
      let file = e.dataTransfer.files[0];
      let URL = window.URL || window.webkitURL;
      let imgURL = URL.createObjectURL(file);
      document.querySelector('.pre').setAttribute('src', imgURL);
    }
    box2.ondragover = function (e) {
      e.preventDefault();
    }
  </script>
</body>
这里是通过  dataTransfer 对象的 files 属性来获取到文件的,并且将其进行预览,我这里所用的将图片进行预览的方式是通过 URL 对象来对其进行url转换的,也可以使用fileReader来实现,具体可以参考我前面的本地通过input:file来上传文件时所用的两种方式,这里。
这样就实现了拖拽上传图片并且预览的功能,可以来看一下效果图:
这里没有对样式进行很细致的调整,可以根据自己的情况进行调整。
总结
这篇文章介绍了两种常见的拖拽的方式,但是其实这两种方式的差别还是非常的明显的,应用场景差别也很大。
一个主要时通过拖拽来改变元素的位置,而另一个一般都是通过拖拽到指定区域来进行文件的上传,各有各的应用场景。