【问题标题】:JavaScript How to Dynamically Move Div by Clicking and DraggingJavaScript 如何通过单击和拖动动态移动 div
【发布时间】:2014-07-25 21:19:32
【问题描述】:

好的,看起来应该很简单。我需要取一个已经存在的 div 并根据窗口内的鼠标位置移动它。我到处搜索,它导致我做同样事情的方式过于复杂,并涉及使用 j-query。我需要严格使用 javascript 来做我想做的事情。

方法:

var mousePosition;
var div;

(function createDiv(){

    div = document.createElement("div");
    div.style.position = "absolute";
    div.style.left = "0px";
    div.style.top = "0px";
    div.style.width = "100px";
    div.style.height = "100px";
    div.style.background = "red";
    div.style.color = "blue";

    div.addEventListener('mousedown', handleKeyPressed, true);

    document.body.appendChild(div);


})();

function handleKeyPressed(event) {

    event.preventDefault();

    mousePosition = {

        x : event.clientX,
        y : event.clientY

    };

    div.style.left = mousePosition.x;
    div.style.top = mousePosition.y;

    //alert("whoa!");

}

【问题讨论】:

  • jQuery 可以做到这一点,它对所有事情都很棒。添加 jQuery UI,你就可以开箱即用了。
  • @adeneo jQuery 是一个 javascript 库,想要了解 javascript 而不是 jquery,尽管我知道使用它是常规的,目前对学习它不感兴趣。只是研究纯 javascript。

标签: javascript html onmousedown


【解决方案1】:

我认为您正在寻找类似的东西

var mousePosition;
var offset = [0,0];
var div;
var isDown = false;

div = document.createElement("div");
div.style.position = "absolute";
div.style.left = "0px";
div.style.top = "0px";
div.style.width = "100px";
div.style.height = "100px";
div.style.background = "red";
div.style.color = "blue";

document.body.appendChild(div);

div.addEventListener('mousedown', function(e) {
    isDown = true;
    offset = [
        div.offsetLeft - e.clientX,
        div.offsetTop - e.clientY
    ];
}, true);

document.addEventListener('mouseup', function() {
    isDown = false;
}, true);

document.addEventListener('mousemove', function(event) {
    event.preventDefault();
    if (isDown) {
        mousePosition = {

            x : event.clientX,
            y : event.clientY

        };
        div.style.left = (mousePosition.x + offset[0]) + 'px';
        div.style.top  = (mousePosition.y + offset[1]) + 'px';
    }
}, true);

FIDDLE

【讨论】:

  • 虽然有点紧张。
  • 因为它总是在鼠标指针的左上角,你必须计算元素相对于你点击的位置的偏移量,但这本身几乎就是一个问题。
  • @adeneo 谢谢。 :) 虽然你可以简单地称我为白痴,因为忘记将 px 添加到 div.style.left = e.clientX; 的末尾。但这让我更加感激。
  • @StoneAgeCoder - 是的,在普通的 JS 单元中是必需的。让我们看看我们是否无法修复抖动,一秒钟。
  • 这是迄今为止我见过的最好的解决方案。该脚本很小且易于理解,其结果比我在各种浏览器上看到的任何其他脚本都好。我不得不发表评论和投票,如果只是为了将来再次找到这个。
【解决方案2】:

支持触摸输入

所有其他答案(包括接受的答案)都不适用于触摸输入。 触摸输入的事件与鼠标输入的事件不同。请参阅 MDN 上的 Using Touch Events

以下代码 sn-p 甚至可以使用触摸输入。我已经突出显示了需要添加以支持触摸设备的所有代码行。
这里的基本思想是类列表中包含draggable 的每个元素都应该是可拖动的。当您有大量需要拖动的元素时,这个概念更容易理解。

请参阅this Glitch 页面和下面的演示。

const d = document.getElementsByClassName("draggable");

for (let i = 0; i < d.length; i++) {
  d[i].style.position = "relative";
}

function filter(e) {
  let target = e.target;

  if (!target.classList.contains("draggable")) {
    return;
  }

  target.moving = true;

  //NOTICE THIS ? Check if Mouse events exist on users' device
  if (e.clientX) {
    target.oldX = e.clientX; // If they exist then use Mouse input
    target.oldY = e.clientY;
  } else {
    target.oldX = e.touches[0].clientX; // Otherwise use touch input
    target.oldY = e.touches[0].clientY;
  }
  //NOTICE THIS ? Since there can be multiple touches, you need to mention which touch to look for, we are using the first touch only in this case

  target.oldLeft = window.getComputedStyle(target).getPropertyValue('left').split('px')[0] * 1;
  target.oldTop = window.getComputedStyle(target).getPropertyValue('top').split('px')[0] * 1;

  document.onmousemove = dr;
  //NOTICE THIS ?
  document.ontouchmove = dr;
  //NOTICE THIS ?

  function dr(event) {
    event.preventDefault();

    if (!target.moving) {
      return;
    }
    //NOTICE THIS ?
    if (event.clientX) {
      target.distX = event.clientX - target.oldX;
      target.distY = event.clientY - target.oldY;
    } else {
      target.distX = event.touches[0].clientX - target.oldX;
      target.distY = event.touches[0].clientY - target.oldY;
    }
    //NOTICE THIS ?

    target.style.left = target.oldLeft + target.distX + "px";
    target.style.top = target.oldTop + target.distY + "px";
  }

  function endDrag() {
    target.moving = false;
  }
  target.onmouseup = endDrag;
  //NOTICE THIS ?
  target.ontouchend = endDrag;
  //NOTICE THIS ?
}
document.onmousedown = filter;
//NOTICE THIS ?
document.ontouchstart = filter;
//NOTICE THIS ?
.draggable {
  width: 100px;
  height: 100px;
  background: red;
}
&lt;div class="draggable"&gt;&lt;/div&gt;

【讨论】:

    【解决方案3】:

    检查这是否比 adeneo 更平滑:FIDDLE

    var m = document.getElementById('move');
    m.addEventListener('mousedown', mouseDown, false);
    window.addEventListener('mouseup', mouseUp, false);
    
    function mouseUp() {
        window.removeEventListener('mousemove', move, true);
    }
    
    function mouseDown(e) {
        window.addEventListener('mousemove', move, true);
    }
    
    function move(e) {
        m.style.top = e.clientY + 'px';
        m.style.left = e.clientX + 'px';
    };
    

    【讨论】:

    • 我没有发现这比接受的答案更流畅。这实际上有点跳动。我做错了吗?
    • 是的。接受的答案现在比我的更顺利。请使用已接受的答案。
    • 你好,你能帮我解决这个问题吗?我无法拖动鼠标滚轮stackoverflow.com/questions/70444738/…
    【解决方案4】:

    我刚刚对@adeneo 非常有效的答案做了一个小改动。 如果所有内容都包含在一个函数中,并且每个事件都附加到 div,那么您可以将其用作库的一部分。

    调用以下函数传递一个 id。如果 div 不存在,则创建它。

    function drag_div(div_id){
    var div;
    
    div = document.getElementById(div_id);
    
    if(div == null){
       div = document.createElement("div");
       div.id = div_id;
       div.style.position = "absolute";
       div.style.left = "0px";
       div.style.top = "0px";
       div.style.width = "100px";
       div.style.height = "100px";
       div.style.background = "red";
       div.style.color = "blue";
       document.body.appendChild(div);
    }
    
    div.addEventListener('mousedown', function(e) {
        div.isDown = true;
        div.offset = [
            div.offsetLeft - e.clientX,
            div.offsetTop - e.clientY
        ];
    }, true);
    
    div.addEventListener('mouseup', function() {
        div.isDown = false;
    }, true);
    
    div.addEventListener('mousemove', function(event) {
        event.preventDefault();
        if (div.isDown) {
            div.mousePosition = {
    
                x : event.clientX,
                y : event.clientY
    
            };
            div.style.left = (div.mousePosition.x + div.offset[0]) + 'px';
            div.style.top  = (div.mousePosition.y + div.offset[1]) + 'px';
        }
    }, true);
    }
    

    【讨论】:

    • 感谢图书馆的想法。但是当你快速移动鼠标时,div 会卡住。 mousemove 事件应该被添加到文档中。
    • 你好,你能帮我解决这个问题吗?我无法拖动鼠标滚轮stackoverflow.com/questions/70444738/…
    【解决方案5】:

    您可以将其用作库。完美运行。我在 github 上找到了它,但有时它会卡住,因为共享者将“mouseup”放到元素上。我将其更改为文档并解决了问题。这是固定版本

    'use strict';
    
    /**
     * Makes an element draggable.
     *
     * @param {HTMLElement} element - The element.
     */
    function draggable(element) {
        var isMouseDown = false;
    
        // initial mouse X and Y for `mousedown`
        var mouseX;
        var mouseY;
    
        // element X and Y before and after move
        var elementX = 0;
        var elementY = 0;
    
        // mouse button down over the element
        element.addEventListener('mousedown', onMouseDown);
    
        /**
         * Listens to `mousedown` event.
         *
         * @param {Object} event - The event.
         */
        function onMouseDown(event) {
            mouseX = event.clientX;
            mouseY = event.clientY;
            isMouseDown = true;
        }
    
        // mouse button released
        document.addEventListener('mouseup', onMouseUp);
    
        /**
         * Listens to `mouseup` event.
         *
         * @param {Object} event - The event.
         */
        function onMouseUp(event) {
            isMouseDown = false;
            elementX = parseInt(element.style.left) || 0;
            elementY = parseInt(element.style.top) || 0;
        }
    
        // need to attach to the entire document
        // in order to take full width and height
        // this ensures the element keeps up with the mouse
        document.addEventListener('mousemove', onMouseMove);
    
        /**
         * Listens to `mousemove` event.
         *
         * @param {Object} event - The event.
         */
        function onMouseMove(event) {
            if (!isMouseDown) return;
            var deltaX = event.clientX - mouseX;
            var deltaY = event.clientY - mouseY;
            element.style.left = elementX + deltaX + 'px';
            element.style.top = elementY + deltaY + 'px';
        }
    }
    

    【讨论】:

      【解决方案6】:

      jquery 更容易部署。我很惊讶你说你不想学习它。

      您可以将 jquery 文件保存在本地计算机中,这样您就不需要互联网 使用 jquery 功能。

      就我而言,我已将其保存在工具文件夹中。所以我不需要上网。

      对于上面回答的所有 js 多行 js 代码,您只需要一小行。

       <script src="/common/tools/jquery-1.10.2.js"></script>
       <script src="/common/tools/jquery-ui.js"></script>
      
       <script>
         $(function() {
         $( "#mydiv_to_make_draggable" ).draggable();
         });
      </script>
      

      【讨论】:

      • JQuery 很容易使用,但是,任何人都可以使用它。我也是一个喜欢从头开始编写所有代码的程序员。如果您在代码中包含 JQuery 库,并且只使用其中的一两个函数,则会浪费大量空间。
      • +1 - 现在有太多人跳到 jQuery,他们不 (1) 理解或认识到为什么 jQuery 存在于首位, (2) 评估当前环境是否需要这样一个大型代码库。更多的时候 - 使用带有 ES5 转换的纯 ES6 将导致未来的代码,更少的膨胀,更好地理解编程和它是如何工作的。不是“让它工作”。
      【解决方案7】:

      这是包含触摸输入的另一种方法。

      dragElement(document.getElementById('mydiv'));
      
      function dragElement(element) {
          var startX = 0, startY = 0, endX = 0, endY = 0;
          element.onmousedown = dragStart;
          element.ontouchstart = dragStart;
      
          function dragStart(e) {
              e = e || window.event;
              e.preventDefault();
              // mouse cursor position at start  
              if (e.clientX) {  // mousemove
                  startX = e.clientX;
                  startY = e.clientY;
              } else { // touchmove - assuming a single touchpoint
                  startX = e.touches[0].clientX
                  startY = e.touches[0].clientY
              }
              document.onmouseup = dragStop;
              document.ontouchend = dragStop;
              document.onmousemove = elementDrag;  // call whenever the cursor moves
              document.ontouchmove = elementDrag;
          }
      
          function elementDrag(e) {
              e = e || window.event;
              e.preventDefault();
              // calculate new cursor position
              if (e.clientX) {
                  endX = startX - e.clientX;
                  endY = startY - e.clientY;
                  startX = e.clientX;
                  startY = e.clientY;
              } else {
                  endX = startX - e.touches[0].clientX;
                  endY = startY - e.touches[0].clientY;
                  startX = e.touches[0].clientX;
                  startY = e.touches[0].clientY;
              }
              // set the new position
              element.style.left = (element.offsetLeft - endX) + "px";
              element.style.top = (element.offsetTop - endY) + "px";
          }
      
          function dragStop() {
              // stop moving on touch end / mouse btn is released 
              document.onmouseup = null;
              document.onmousemove = null;
              document.ontouchend = null;
              document.ontouchmove = null;
          }
      }
      

      【讨论】:

        【解决方案8】:

        已接受答案并添加了触摸

        adeno 接受的答案非常优雅且效果很好。但是它只适用于鼠标点击,所以这里是一个包含触摸输入的修改版本:

        var position;
        var offset = [0,0];
        var isDown = false;
        
        function makeDraggable(el){
        
            ['mousedown', 'touchstart'].forEach( evt => 
                el.addEventListener(evt, pickup, true)
            );
            
            ['mousemove', 'touchmove'].forEach( evt => 
                el.addEventListener(evt, move, true)
            );
        
            ['mouseup', 'touchend'].forEach( evt => 
                el.addEventListener(evt, drop, true)
            );      
                
            function pickup(e) {
                isDown = true;
                if (e.clientX) {
                    offset = [el.offsetLeft - e.clientX, el.offsetTop - e.clientY];
                }
                else if (e.touches) {  
                    // for touch devices, use 1st touch only
                    offset = [el.offsetLeft - e.touches[0].pageX, el.offsetTop - e.touches[0].pageY];
                }       
            }
            function move(e) {
                if (isDown) {
                    if (e.clientX) {
                        position = {x : e.clientX, y : e.clientY};
                    }
                    else if (e.touches) {
                        position = {x : e.touches[0].pageX, y : e.touches[0].pageY};            
                    }           
                    el.style.left = (position.x + offset[0]) + 'px';
                    el.style.top  = (position.y + offset[1]) + 'px';
                }
            }
            function drop(e) {
                // seems not to be needed for Android Chrome
                // and modern browsers on Mac & PC
                // but is required for iPad & iPhone
                isDown = false;     
                el.style.left = (position.x + offset[0]) + 'px';
                el.style.top  = (position.y + offset[1]) + 'px';
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-10
          • 2012-08-16
          • 1970-01-01
          • 2020-04-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多