拖放 
拖放动作过程

1 被拖动元素 
在 HTML 中,除了图像、链接和选择的文本默认的可拖拽行为之外,其他元素在默认情况下是不可拖拽的。
要使其他的 HTML 元素可拖拽,必须:
- 将想要拖拽的元素的 
draggable属性设置成draggable="true"。 - 监听 
dragstart事件,并设置拖拽数据event.dataTransfer.setData('key', 'value') 
2 目标元素 
- 监听 
dragenter和dragover(常用) 事件,阻止默认的处理,使得该元素能够接收drop事件,如:<div ondragover="event.preventDefault()"> - 监听 
drop事件,获取拖拽数据jsevent.preventDefault() event.dataTransfer.getData('key', 'value') 
3 事件 
| 元素 | 事件 | On 型事件处理程序 | 触发时刻 | 
| 被拖动元素 | dragstart | ondragstart | 按下鼠标,开始移动时触发 | 
| drag | ondrag | 当被拖动元素离开原位置,鼠标按住不放(不管鼠标是否移动)时触发,所以该事件会触发很多次 | |
| dragend | ondragend | 松开鼠标时(不管鼠标是否落在目标元素上)触发 (比如松开鼠标按键或敲“Esc”键) | |
| 目标元素 | dragenter | ondragstart | 按住、移动鼠标,当进入目标元素时触发 | 
| dragover | ondragover | 鼠标在目标元素上方时触发(每 100 毫秒触发一次) | |
| dragleave | ondragleave | 按住、移动鼠标当离开目标元素时触发 | |
| drop | ondrop | 鼠标在目标元素上松开时触发 | 
其中常用 dragstart、dragover、drop。
一个关于事件执行顺序的例子:
<style>
  .d1 {
    width: 40px;
    height: 40px;
    background: url(".https://image.newarea.site/error.png") no-repeat;
  }
  .d2 {
    width:350px;
    height:70px;
    padding:10px;
    border:1px solid #aaaaaa;
  }
</style>
<body>
  <div class="d1" draggable="true"></div>
  <br>
  <div class="d2"></div>
  <script>
    const d1 = document.querySelector('.d1')
    const d2 = document.querySelector('.d2')
    d1.ondragstart = function (ev) {
      console.log('dragstart')
      ev.dataTransfer.setData('url1','.https://image.newarea.site/error.png');
    }
    d1.ondrag = function () {
      console.log('drag')
    }
    d1.ondragend = function () {
      console.log('dragend')
    }
    d2.ondragenter = function () {
      console.log('dragenter')
    }
    d2.ondragover = function (ev) {
      ev.preventDefault()
    }
    d2.ondragleave = function () {
      console.log('dragleave')
    }
    d2.ondrop = function (ev) {
      ev.preventDefault()
      console.log('drop')
      const img = new Image()
      img.src = ev.dataTransfer.getData('url1')
      ev.target.appendChild(img)
    }
  </script>
</body>

4 dropEffect、effectAllowed 
dropEffect 
dropEffect 属性顾名思意拖拽效果,在 PC web 端主要表现在鼠标手形上。不同的 dropEffect 值,鼠标的手形效果是不一样的。值可以是 move,copy,link 和 none。
dropEffect 属性的设置主要用在 dragenter 和 dragover 事件中,同时受 effectAllowed 属性影响。
例如,我们在 dragstart 的时候设置 effectAllowed 属性值为 none,则 dropEffect 只能表现为 none,而不会出现其他手形,即使设置了其他手形对应的属性值。
effectAllowed 
effectAllowed 和 dropEffect 通常应用的事件方法名不一样,effectAllowed 多用在 dragstart 事件中,而 dropEffect 属性的设置主要用在 dragenter 和 dragover 事件中。
effectAllowed 和 dropEffect 的彼此间是有制约关系,当我们给 effectAllowed 设置了对应的属性值,则 dropEffect 只能设置为 effectAllowed 允许的值,否则是无效的。
举个例子,如果我们设置 effectAllowed 值为 copyMove,则 dropEffect 只有 copy 和 move 这两个属性值才有效。
effectAllowed 看上去很屌,但实际应用的时候相当鸡肋。我们通常的拖拽应用是用不到这个的。只要下面这个场景,那就是当我们有很多个元素需要拖拽,但是需要像垃圾一样分门别类的时候,effectAllowed 就有用了。
5 数据类型 
常用 'text/plain'
5.1 拖动图像 
<img src=".https://image.newarea.site/error.png" class="d1">
<br>
<input>
<script>
  const input = document.querySelector('input')
  input.ondrop = function (ev) {
    const items = ev.dataTransfer.items
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      console.log(item, ev.dataTransfer.getData(item.type))
    }
  }
</script>
5.2 拖动链接 
<a href="https://www.baidu.com" >百度</a>
<br>
<input>
<script>
  const input = document.querySelector('input')
  input.ondrop = function (ev) {
    const items = ev.dataTransfer.items
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      console.log(item, ev.dataTransfer.getData(item.type))
    }
  }
</script>
5.3 拖动选择的文本 
<p>拖放功能真强大</p>
<input>
<script>
  const input = document.querySelector('input')
  input.ondrop = function (ev) {
    const items = ev.dataTransfer.items
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      console.log(item, ev.dataTransfer.getData(item.type))
    }
  }
</script>
5.4 拖动元素 
<div draggable="true">拖放功能真强大</div>
<input>
<script>
  const div = document.querySelector('div')
  const input = document.querySelector('input')
  div.ondragstart = function (ev) {
    // 自定义
    // ev.dataTransfer.setData('name', 'Jack')
    ev.dataTransfer.setData('text/plain', 'Jack')
  }
  input.ondragover = function (ev) {
    ev.preventDefault()
  }
  input.ondrop = function (ev) {
    const items = ev.dataTransfer.items
    for (let i = 0; i < items.length; i++) {
      const item = items[i]
      console.log(item, ev.dataTransfer.getData(item.type))
    }
  }
</script>