Blog icon indicating copy to clipboard operation
Blog copied to clipboard

HTML5中拖曳与拖放的学习

Open pramper opened this issue 9 years ago • 0 comments

很多场景下都需要拖曳或拖放元素的功能,例如拖曳一个登陆框或提示框等。今天温习了一下传统的拖曳方式,并学习了一下HTML5提供的原生拖放功能,总结了一下。

传统拖放元素的方式

实现步骤如下:

  1. 鼠标选中元素,触发onmousedown事件
  2. 开始拖动,触发onmousemove事件,元素跟随鼠标移动
  3. 释放鼠标,触发onmouseup事件

其实关键就是在移动过程中将鼠标的坐标不断赋值给被拖动的元素,从而达到拖曳元素的效果。

核心实现代码如下,进行了简单的封装,使用时调用drag函数并传入点击的元素和被拖曳的元素即可:

var drag = (function() {
    var flag = false    // 表示是否拖曳
    /**
     * @param  {[element]} bar:点击的元素,如登录框的头部
     * @param  {[element]} target:被拖曳的元素
     */
    function startDrag(bar, target) {
        var innerX, innerY  // 鼠标距bar的左边距和上边距的距离

        bar.addEventListener('mousedown', mousedown, false)
        document.addEventListener('mouseup', mouseup, false)
        document.addEventListener('mousemove', mousemove, false)                    
        //获取target的CSS 
        var targetCSS = document.defaultView.getComputedStyle(target, null)

        function mousedown() {
            flag = true //鼠标点下时,表示才能被拖曳
            innerX = event.clientX - parseInt(targetCSS.left)
            innerY = event.clientY - parseInt(targetCSS.top)
        }

        function mousemove() {
            if(flag) {
                target.style.left = event.clientX - innerX + 'px'
                target.style.top = event.clientY - innerY + 'px'
            }

        }

        function mouseup() {
            flag = false //松开鼠标后,元素无法被拖曳
        }

    }
    return startDrag
})();

完整示例

使用HTML5的原生拖放功能

默认情况下元素是不允许被拖曳的,要想拖曳某元素,在元素添加属性draggable="false"。拖动某元素时,如果拖动的区域不允许放置元素,则光标变为禁止符号(圆环中一道反斜杠);在被拖动元素上依次触发以下事件:

  1. dragstart
  2. drag
  3. dragend

按下鼠标并开始拖动元素时,在被拖动元素上首先触发dragstart事件,然后在拖动期间会持续触发drag事件,松开鼠标触发dragend事件。

当被拖曳的元素被拖动到一个有效放置的目标元素时,目标元素会被依次触发以下事件:

  1. dragenter
  2. dragover
  3. drop或dragleave

被拖曳的元素进入该目标的区域时触发dragenter事件,随后持续触发dragover事件,直到元素被被放下触发dropdragleave事件。虽然所有元素都支持放置目标事件,但默认是不允许放置的,drop事件不会发生。把元素变为有效放置目标的方法是阻止dragenterdragover的默认行为。还有,在Firfox 3.5+中,drop事件的默认行为是打开被放到放置目标上的URL,意思就是如果把图像拖放到放置目标上,页面就会转向图像文件。因此,还要取消drop事件的默认行为。核心代码如下:

var drag = function() {

  var boxCSS = document.defaultView.getComputedStyle(box, null)
  var innerX, innerY  // 鼠标距别拖曳元素左边界和上边界的距离
  /**
   * @param  {[element]} el:被拖放的元素
   * @param  {[element]} target:拖放的目标元素 
   */
  function startDrag(el, target) {

    el.addEventListener("dragstart", function() {
      innerX = event.clientX - parseInt(boxCSS.left)
      innerY = event.clientY - parseInt(boxCSS.top)
    }, false)
    el.addEventListener("dragend", function() {
      this.style.left = event.clientX - innerX + 'px'
      this.style.top = event.clientY - innerY + 'px'
    }, false)
    target.addEventListener("dragenter", function() {
      event.preventDefault()
    }, false)
    target.addEventListener("dragover", function() {
      event.preventDefault()
    }, false)
    target.addEventListener("drop", function() {
      event.preventDefault();
    }, false)
  }

  return startDrag
}()

完整示例

总结

个人感觉还是HTML5提供的原生拖放功能好用,浏览器会自动创建一个被拖动元素的半透明副本跟随光标移动,所以不用一直跟踪鼠标的位置,以改变元素的位置。还有,利用HTML的拖放效果还可以在拖曳元素和目标之间交换数据,修改拖曳效果等等。

参考资料

pramper avatar Aug 20 '16 14:08 pramper