【问题标题】:Moveable/draggable <div>可移动/可拖动 <div>
【发布时间】:2012-03-09 04:43:56
【问题描述】:

这是我更新和修改的脚本,它完全可以工作,除了我想通用它...观察****我怎样才能做到这样我就不必每次都做function(e){BOX.Draggable.elemen = e.target || e.srcElement; elementDraggable(e);需要对不同的元素使用可拖动功能吗?

window.onload = addListeners;

var BOX = function(){
  return{
    Draggable: function(){}
  };
}();

function addListeners(){
  document.getElementById('div').addEventListener('contextmenu', menumove, false);
  **document.getElementById('div').addEventListener('mousedown', function(e){BOX.Draggable.elemen = e.target || e.srcElement; elementDraggable(e);}, false);**
}

function elementDraggable(e){
  var e = e || window.event;
  var div = BOX.Draggable.elemen;
  BOX.Draggable.innerX = e.clientX + window.pageXOffset - div.offsetLeft;
  BOX.Draggable.innerY = e.clientY + window.pageYOffset - div.offsetTop;

  window.addEventListener('mousemove', elementMove, false);
  window.addEventListener('mouseup', function(){
    window.removeEventListener('mousemove', elementMove, false);
    }, true);

  function elementMove(e){
    div.style.position = 'absolute';
    div.style.left = e.clientX + window.pageXOffset - BOX.Draggable.innerX + 'px';
    div.style.top = e.clientY + window.pageYOffset - BOX.Draggable.innerY + 'px';
  }
}

【问题讨论】:

标签: javascript draggable move mousemove


【解决方案1】:

你可以选择 jQuery 吗?由于代码已经存在,它使您正在做的事情变得非常简单。

http://jqueryui.com/demos/draggable/

Demo

JavaScript 代码

window.onload = addListeners;

function addListeners(){
    document.getElementById('dxy').addEventListener('mousedown', mouseDown, false);
    window.addEventListener('mouseup', mouseUp, false);

}

function mouseUp()
{
    window.removeEventListener('mousemove', divMove, true);
}

function mouseDown(e){
  window.addEventListener('mousemove', divMove, true);
}

function divMove(e){
    var div = document.getElementById('dxy');
  div.style.position = 'absolute';
  div.style.top = e.clientY + 'px';
  div.style.left = e.clientX + 'px';
}​

【讨论】:

  • 我已经知道如何用 jquery 做到这一点,我正在尝试学习如何用 javascript 手动做到这一点,谢谢。
  • 是的,它没有保存最新的我刚刚意识到它。我正在重写它
  • @AndersonGreen 您必须考虑拖动开始的位置。如果您从 div 的中间开始拖动,则必须将位置偏移。见jsfiddle.net/wfbY8/737(我知道旧评论,但需要回复..)
  • 这是真的 MrRioku 但如果他已经在加载库,那将是他的最佳选择。他不是,所以我为他提供了直接的 JavaScript 代码。
  • 函数mouseDownmouseUp在附加事件时有什么理由将useCapture参数设置为true?而addListeners 函数在附加事件时使用false
【解决方案2】:

这是一个不错的非 jQuery 脚本来拖动 div:http://jsfiddle.net/g6m5t8co/1/

var mydragg = function() {
  return {
    move: function(divid, xpos, ypos) {
      divid.style.left = xpos + 'px';
      divid.style.top = ypos + 'px';
    },
    startMoving: function(divid, container, evt) {
      evt = evt || window.event;
      var posX = evt.clientX,
        posY = evt.clientY,
        divTop = divid.style.top,
        divLeft = divid.style.left,
        eWi = parseInt(divid.style.width),
        eHe = parseInt(divid.style.height),
        cWi = parseInt(document.getElementById(container).style.width),
        cHe = parseInt(document.getElementById(container).style.height);
      document.getElementById(container).style.cursor = 'move';
      divTop = divTop.replace('px', '');
      divLeft = divLeft.replace('px', '');
      var diffX = posX - divLeft,
        diffY = posY - divTop;
      document.onmousemove = function(evt) {
        evt = evt || window.event;
        var posX = evt.clientX,
          posY = evt.clientY,
          aX = posX - diffX,
          aY = posY - diffY;
        if (aX < 0) aX = 0;
        if (aY < 0) aY = 0;
        if (aX + eWi > cWi) aX = cWi - eWi;
        if (aY + eHe > cHe) aY = cHe - eHe;
        mydragg.move(divid, aX, aY);
      }
    },
    stopMoving: function(container) {
      var a = document.createElement('script');
      document.getElementById(container).style.cursor = 'default';
      document.onmousemove = function() {}
    },
  }
}();
#container {
  position: absolute;
  background-color: blue;
}

#elem {
  position: absolute;
  background-color: green;
  -webkit-user-select: none;
  -moz-user-select: none;
  -o-user-select: none;
  -ms-user-select: none;
  -khtml-user-select: none;
  user-select: none;
}
<div id='container' style="width: 600px;height: 400px;top:50px;left:50px;">
  <div id="elem" onmousedown='mydragg.startMoving(this,"container",event);' onmouseup='mydragg.stopMoving("container");' style="width: 200px;height: 100px;">
    <div style='width:100%;height:100%;padding:10px'>
      <select id=test>
        <option value=1>first
          <option value=2>second
      </select>
      <INPUT TYPE=text value="123">
    </div>
  </div>
</div>

【讨论】:

  • 很好的解决方案!它非常通用,并且还确保您不能将 div 移到父容器之外!
  • 不错的例子!另一个问题是,如果您开始拖动并将光标移到绿色框外,则鼠标向上不会注册....换句话说,鼠标向上事件不会在绿色框外注册。
  • Davvit,为容器添加“onmouseout”。
  • stopMoving函数中的var a = document.createElement('script');行有什么用?
【解决方案3】:

好吧,您的运动代码简化为:

div.style.position = "absolute";
div.style.top = e.clientY - (e.clientY - div.offsetTop) + "px";
div.style.left = e.clientX - (e.clientX - div.offsetLeft) + "px";

这里的基本数学 - e.clientXe.clientY 对这里的位置绝对没有影响,所以您只需将 offsetLeft 重新分配给 style.left,顶部也是如此。因此没有任何动静。

你需要做的是当mousedown发生时保存clientXclientY,并在此基础上做减法。

哦,您还错误地设置了事件侦听器。现在的方式是,它运行一次divMove,返回值(此处为undefined)是作为侦听器附加的函数。请改用function(e) {divMove(dxy,e || window.event);}

【讨论】:

  • 我基本明白你在说什么,我可以看出你是对的。但我不完全确定如何将其更改为您所说的。你能放一个sn-p来告诉我你的意思吗?
  • 您在对另一个答案的评论中说您正在尝试学习,所以我不会为您做,但基本上您有两种主要的方法。 1)使用绝对定位,获取当前鼠标坐标并将元素设置为这些坐标。 2) 使用相对定位,取当前位置与起始位置的差值。
  • 谢谢你让我自己做。我几乎可以弄清楚所有事情,只需要一点帮助,因为我不知道 removeEventListener 方法:-)
  • 耶^_^ 我自己的拖放代码只使用elem.onmousemove,将其设置为null 而不是removeEventListener。个人喜好。
【解决方案4】:

我稍微修改了Shaedo's 代码,将其包装在一个函数中,并添加了一个功能,即您可以仅通过元素的一部分或其子元素拖动元素,例如 div 的标题栏。注意在这个demo中,只能拖动红色区域来移动蓝色区域。

function makeDragable(dragHandle, dragTarget) {
  let dragObj = null; //object to be moved
  let xOffset = 0; //used to prevent dragged object jumping to mouse location
  let yOffset = 0;

  document.querySelector(dragHandle).addEventListener("mousedown", startDrag, true);
  document.querySelector(dragHandle).addEventListener("touchstart", startDrag, true);

  /*sets offset parameters and starts listening for mouse-move*/
  function startDrag(e) {
    e.preventDefault();
    e.stopPropagation();
    dragObj = document.querySelector(dragTarget);
    dragObj.style.position = "absolute";
    let rect = dragObj.getBoundingClientRect();

    if (e.type=="mousedown") {
      xOffset = e.clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
      yOffset = e.clientY - rect.top;
      window.addEventListener('mousemove', dragObject, true);
    } else if(e.type=="touchstart") {
      xOffset = e.targetTouches[0].clientX - rect.left;
      yOffset = e.targetTouches[0].clientY - rect.top;
      window.addEventListener('touchmove', dragObject, true);
    }
  }

  /*Drag object*/
  function dragObject(e) {
    e.preventDefault();
    e.stopPropagation();

    if(dragObj == null) {
      return; // if there is no object being dragged then do nothing
    } else if(e.type=="mousemove") {
      dragObj.style.left = e.clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
      dragObj.style.top = e.clientY-yOffset +"px";
    } else if(e.type=="touchmove") {
      dragObj.style.left = e.targetTouches[0].clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
      dragObj.style.top = e.targetTouches[0].clientY-yOffset +"px";
    }
  }

  /*End dragging*/
  document.onmouseup = function(e) {
    if (dragObj) {
      dragObj = null;
      window.removeEventListener('mousemove', dragObject, true);
      window.removeEventListener('touchmove', dragObject, true);
    }
  }
}

makeDragable('#handle', '#moveable')
#moveable {
    width: 100px;
    height: 100px;
    background: blue;
}

#handle {
    width: 50px;
    height: 50px;
    cursor: move;
    background: red;
}
<div id="moveable">
    <div id="handle">
    </div>
</div>

【讨论】:

  • 这绝对应该是公认的答案:它的方法是通用的,易于使用,甚至支持触摸事件。哦,它考虑到要拖动的容器通常与您拖动它的手柄不同。非常感谢!! :)
【解决方案5】:

在尝试了 jnoreiga 接受的答案后,我发现拖动的元素突然卡到左上角,而不是保持相同的相对位置,这很烦人。

这个 sn-p 通过偏移量防止了上述尴尬的行为,并提供了一个简单的界面来一次创建一个或通过 forEach 调用或类似方法来创建可拖动元素。

window.onload = function() {
  draggable(document.getElementById('foo'));
}

function draggable(el) {
  el.addEventListener('mousedown', function(e) {
    var offsetX = e.clientX - parseInt(window.getComputedStyle(this).left);
    var offsetY = e.clientY - parseInt(window.getComputedStyle(this).top);
    
    function mouseMoveHandler(e) {
      el.style.top = (e.clientY - offsetY) + 'px';
      el.style.left = (e.clientX - offsetX) + 'px';
    }

    function reset() {
      window.removeEventListener('mousemove', mouseMoveHandler);
      window.removeEventListener('mouseup', reset);
    }

    window.addEventListener('mousemove', mouseMoveHandler);
    window.addEventListener('mouseup', reset);
  });
}
/* The only required styling is position: absolute */
#foo {
  position: absolute;
  border: 1px solid black;
  overflow: hidden;
}

/* Prevents inconsistent highlighting of element while being dragged
   Copied from https://stackoverflow.com/questions/826782 */
.noselect {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}
&lt;div id="foo" class="noselect"&gt;This is a draggable div!&lt;/div&gt;

【讨论】:

    【解决方案6】:

    给我所有的朋友:

        function initDrag(div) {
            div.addEventListener('mousedown', e => {
                if (e.target === div){
                    startDrag(e, div);
                };
            });
        };
    
        function startDrag(e, div) {
    
            const offsetX = e.offsetX;
            const offsetY = e.offsetY;
    
            const controller = new AbortController();
    
            div.style.cursor = "grabbing";
    
            document.addEventListener('mousemove', e => {
                div.style.top = window.scrollY + e.clientY - offsetY + 'px';
                div.style.left = window.scrollX + e.clientX - offsetX + 'px';
            }, { signal: controller.signal }, true);
    
            'mouseup,blur'.split(',').forEach(e => {
                document.addEventListener(e, () => {
                    controller.abort();
                    div.style.cursor = "grab";
                }, { once: true }, true);
            });
        };
    

    【讨论】:

      【解决方案7】:

      “niente00”代码的附加方法。

      init : function(className){
          var elements = document.getElementsByClassName(className);
          for (var i = 0; i < elements.length; i++){
              elements[i].onmousedown = function(){mydragg.startMoving(this,'container',event);};
              elements[i].onmouseup = function(){mydragg.stopMoving('container');};
              }
          }
      

      【讨论】:

        【解决方案8】:

        dragend 事件中使用clientYclientXpageYpageX 的任何解决方案在 Firefox 中将完全失败。来源:Bugzilla: Bug #505521, Set screen coordinates during HTML5 drag event.

        我们如何克服这个限制? documentdrop 事件也触发 与拖动元素的dragend 事件同时触发。但是,我们可以在 Firefox 中看到像 clientYclientX 这样的东西。所以,我们就用它吧。

        两个工作演示,100% 仅 JavaScript 的解决方案:SO 代码片段和 JSBin

        var startx = 0;
        var starty = 0;
        dragStartHandler = function(e) {
          startx = e.clientX;
          starty = e.clientY;
        }
        
        dragOverHandler = function(e) {
          e.preventDefault();
          return false;
        }
        
        dragEndHandler = function(e) {
          if(!startx || !starty) {
            return false;
          }
          
          var diffx = e.clientX - startx;
          var diffy = e.clientY - starty;
          
          var rect = e.target.getBoundingClientRect();
        
        var offset = { 
                        top: rect.top + window.scrollY, 
                        left: rect.left + window.scrollX, 
                    };
          
          var newleft = offset.left + diffx;
          var newtop = offset.top + diffy;
          
          e.target.style.position = 'absolute';
          e.target.style.left = newleft + 'px';
          e.target.style.top = newtop + 'px';
          
          startx = 0;
          starty = 0;
        }
        
        document.getElementsByClassName("draggable")[0].addEventListener('dragstart', dragStartHandler);
        
        document.addEventListener('dragover', dragOverHandler);
        document.addEventListener('drop', dragEndHandler);
        .draggable {
          border: 1px solid black;
          cursor: move;
          width:250px;
        };
        <!DOCTYPE html>
        <html>
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width">
          <title>JS Bin</title>
        </head>
        <body>
          
          <BR><BR><BR>
        
          <div id="draggable1" class="draggable" draggable="true">
            Hey, try to drag this element!
          </div>
          
        </body>
        </html>

        说明:

        • dragStartHandler() :绑定到可拖动元素。在这里,我们所做的只是在开始时记录当前的 x/y 坐标。
        • dragOverHandler() :这是绑定到文档的,这样我们就可以覆盖默认的拖动行为。这是执行任何类型的拖放操作所必需的。
        • dragEndHandler() :绑定到documentdrop。通常,我们希望它绑定到elementdragend,但是由于缺少clientYclientX,我们将它绑定到文档。这正是您在调用 dragend 时想要发生的事情,除非您有 x/y 坐标。

        使用的公式是:

        set style to: (current position) - (original position)
        

        这很复杂,但是要计算和应用样式,仅针对 x 维度,代码是...

        var diffx = e.clientX - startx;
        var rect = e.target.getBoundingClientRect();
        var offset = { 
                left: rect.left + window.scrollX, 
            };
        var newleft = offset.left + diffx;
        e.target.style.position = 'absolute';
        e.target.style.left = newleft + 'px';
        

        【讨论】:

          猜你喜欢
          • 2013-03-25
          • 1970-01-01
          • 1970-01-01
          • 2013-04-28
          • 2023-03-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          相关资源
          最近更新 更多