【问题标题】:Draggable div without jQuery UI没有 jQuery UI 的可拖动 div
【发布时间】:2012-01-24 00:59:52
【问题描述】:

我正在尝试在不使用 jQuery UI 的情况下使 div 可拖动。

但是,我坚持使用下面的代码。我知道我应该使用相对于容器 div 的鼠标位置(div 将在其中被拖动),并且我应该设置 div 相对于这些值的偏移量。

我只是不知道怎么做。有什么线索吗?

这是(当然)不起作用的代码:

var X, Y;

$(this).mousedown(function() {
    $(this).offset({ 
        left: X, 
        top: Y
    });
});

$("#containerDiv").mousemove(function(event) {
    X = event.pageX;
    Y = event.pageY;
});

【问题讨论】:

    标签: jquery html draggable


    【解决方案1】:

    这是一个真正简单的例子,可以帮助你入门:

    $(document).ready(function() {
        var $dragging = null;
    
        $(document.body).on("mousemove", function(e) {
            if ($dragging) {
                $dragging.offset({
                    top: e.pageY,
                    left: e.pageX
                });
            }
        });
    
    
        $(document.body).on("mousedown", "div", function (e) {
            $dragging = $(e.target);
        });
    
        $(document.body).on("mouseup", function (e) {
            $dragging = null;
        });
    });
    

    示例: http://jsfiddle.net/Jge9z/

    我知道我将使用相对于容器 div 的鼠标位置(应在其中拖动 div),并且我将设置 div 相对于这些值的偏移量。

    对此不太确定。在我看来,在拖放中您总是希望使用元素相对于文档的偏移量。

    如果您的意思是要将拖动限制在特定区域,这是一个更复杂的问题(但仍然可行)。

    【讨论】:

    • 效果很好,但拖动在移动设备上不起作用。如何更改此代码以使其也能在移动设备上运行?
    • 不确定。你可能想看看touch events
    • 我建议通过添加mouseleave 事件来扩展代码,例如$("body").mouseleave(function(e) { $dragging = null; }) 以捕捉在浏览器窗口外释放按下的按钮。
    • 还有Drag and Drop HTML5 API可以用
    • 它的工作,但位置固定和绝对的小问题
    【解决方案2】:

    这是另一个更新的代码:

    $(document).ready(function() {
        var $dragging = null;
        $('body').on("mousedown", "div", function(e) {
            $(this).attr('unselectable', 'on').addClass('draggable');
            var el_w = $('.draggable').outerWidth(),
                el_h = $('.draggable').outerHeight();
            $('body').on("mousemove", function(e) {
                if ($dragging) {
                    $dragging.offset({
                        top: e.pageY - el_h / 2,
                        left: e.pageX - el_w / 2
                    });
                }
            });
            $dragging = $(e.target);
        }).on("mouseup", ".draggable", function(e) {
            $dragging = null;
            $(this).removeAttr('unselectable').removeClass('draggable');
        });
    });​
    

    演示: http://jsfiddle.net/tovic/Jge9z/31/


    我为此线程创建了一个简单的插件。

    // Simple JQuery Draggable Plugin
    // https://plus.google.com/108949996304093815163/about
    // Usage: $(selector).drags();
    // Options:
    // handle            => your dragging handle.
    //                      If not defined, then the whole body of the
    //                      selected element will be draggable
    // cursor            => define your draggable element cursor type
    // draggableClass    => define the draggable class
    // activeHandleClass => define the active handle class
    //
    // Update: 26 February 2013
    // 1. Move the `z-index` manipulation from the plugin to CSS declaration
    // 2. Fix the laggy effect, because at the first time I made this plugin,
    //    I just use the `draggable` class that's added to the element
    //    when the element is clicked to select the current draggable element. (Sorry about my bad English!)
    // 3. Move the `draggable` and `active-handle` class as a part of the plugin option
    // Next update?? NEVER!!! Should create a similar plugin that is not called `simple`!
    
    (function($) {
        $.fn.drags = function(opt) {
    
            opt = $.extend({
                handle: "",
                cursor: "move",
                draggableClass: "draggable",
                activeHandleClass: "active-handle"
            }, opt);
    
            var $selected = null;
            var $elements = (opt.handle === "") ? this : this.find(opt.handle);
    
            $elements.css('cursor', opt.cursor).on("mousedown", function(e) {
                if(opt.handle === "") {
                    $selected = $(this);
                    $selected.addClass(opt.draggableClass);
                } else {
                    $selected = $(this).parent();
                    $selected.addClass(opt.draggableClass).find(opt.handle).addClass(opt.activeHandleClass);
                }
                var drg_h = $selected.outerHeight(),
                    drg_w = $selected.outerWidth(),
                    pos_y = $selected.offset().top + drg_h - e.pageY,
                    pos_x = $selected.offset().left + drg_w - e.pageX;
                $(document).on("mousemove", function(e) {
                    $selected.offset({
                        top: e.pageY + pos_y - drg_h,
                        left: e.pageX + pos_x - drg_w
                    });
                }).on("mouseup", function() {
                    $(this).off("mousemove"); // Unbind events from document
                    if ($selected !== null) {
                        $selected.removeClass(opt.draggableClass);
                        $selected = null;
                    }
                });
                e.preventDefault(); // disable selection
            }).on("mouseup", function() {
                if(opt.handle === "") {
                    $selected.removeClass(opt.draggableClass);
                } else {
                    $selected.removeClass(opt.draggableClass)
                        .find(opt.handle).removeClass(opt.activeHandleClass);
                }
                $selected = null;
            });
    
            return this;
    
        };
    })(jQuery);
    

    演示: http://tovic.github.io/dte-project/jquery-draggable/index.html

    【讨论】:

    • 如果您使用此代码$selected = $(this).parent(); 行38:59您正在迫使开发人员使用固定的html 结构。您假设父级将是完整的structure 移动,但是如果您分配一个类,例如class='draggableContainer',您可以执行$selected = $(this).closest(".draggableContainer"); 之类的操作,您现在可以使用任何html 结构并且它可以工作.但总的来说很酷$hit 工作真的很酷
    • 另外,如果你使用这个简单的plugin,你必须意识到如果你在可拖动容器内有handler events会激活它们,你必须确保无论你在你内部执行什么该处理程序的功能来自预期事件,而不是来自 mouseup(拖动)事件。或者尝试在插件中使用event.stopPropagation(),我试过但我无法阻止它。我不知道该放在哪里。
    • 我正在使用这个插件,但是当您设置为可拖动的元素具有 工作并且用户体验得到改进
    【解决方案3】:

    这是我的贡献:

    http://jsfiddle.net/g6m5t8co/1/

    <!doctype html>
    <html>
        <head>
            <style>
                #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;
                }
            </style>
            <script>
                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(){}
                        },
                    }
                }();
    
            </script>
        </head>
        <body>
            <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>  
        </body>
    </html>
    

    【讨论】:

    • 干得好...仅使用 javascript nice +1
    • 太好了,唯一的问题是如果你有一个绝对定位的元素,在 mousedown 时它认为它在顶部和左侧 0 - 有没有一种简单的方法让它在拖动之前先保持当前位置?
    • @DarrenSweeney:为#elem 调用getBoundingClientRect(),然后使用该矩形的top/left 来初始化divTop/divLeft!奖励:您将不再需要任何预设,或 style 任何东西。
    • 这个比其他答案表现得更好。干得好。
    • var a = document.createElement('script'); 是做什么的?
    【解决方案4】:

    没有 Jquery 解决方案 - 基本

    最基本的可拖动代码是:

    Element.prototype.drag = function(){
    
       var mousemove = function(e){ // document mousemove
    
           this.style.left = ( e.clientX - this.dragStartX ) + 'px';
           this.style.top  = ( e.clientY - this.dragStartY ) + 'px';
    
       }.bind(this);
    
       var mouseup = function(e){ // document mouseup
    
           document.removeEventListener('mousemove',mousemove);
           document.removeEventListener('mouseup',mouseup);
    
       }.bind(this);
    
       this.addEventListener('mousedown',function(e){ // element mousedown
    
           this.dragStartX = e.offsetX;
           this.dragStartY = e.offsetY;
    
           document.addEventListener('mousemove',mousemove);
           document.addEventListener('mouseup',mouseup);
    
       }.bind(this));
    
       this.style.position = 'absolute' // fixed might work as well
    
    }
    

    然后使用(非jquery):

    document.querySelector('.target').drag();
    

    或在 jquery 中:

    $('.target')[0].drag();
    

    注意:被拖动的元素应该有一个position:absolute 或position:fixed 应用于它的左侧,顶部移动工作......

    下面的 codepen 有一些更“高级”的功能:dragStart、dragStop 回调、附加的 css 类以在拖动时删除其他元素的文本选择,还有一个拖放功能......

    签出以下代码笔:

    http://codepen.io/anon/pen/VPPaEK

    它基本上是在需要拖动的元素上设置一个'mousedown'事件,然后绑定和取消绑定文档mousemove来处理移动。

    可拖动手柄

    为了给元素设置一个可拖动的句柄

    Element.prototype.drag = function( setup ){
    
       var setup = setup || {};
    
       var mousemove = function(e){ // document mousemove
    
           this.style.left = ( e.clientX - this.dragStartX ) + 'px';
           this.style.top  = ( e.clientY - this.dragStartY ) + 'px';
    
       }.bind(this);
    
       var mouseup = function(e){ // document mouseup
    
           document.removeEventListener('mousemove',mousemove);
           document.removeEventListener('mouseup',mouseup);
    
       }.bind(this);
    
       var handle = setup.handle || this;
    
       handle.addEventListener('mousedown',function(e){ // element mousedown
    
           this.dragStartX = e.offsetX;
           this.dragStartY = e.offsetY;
    
           document.addEventListener('mousemove',mousemove);
           document.addEventListener('mouseup',mouseup);
    
           handle.classList.add('dragging');
    
       }.bind(this)); 
    
       handle.classList.add('draggable');
    
       this.style.position = 'absolute' // fixed might work as well
    
    }
    

    上面的代码是这样使用的:

    var setup = {
       handle : document.querySelector('.handle')
    };
    
    document.querySelector('.box').drag(setup);
    

    添加 CSS 以消除可选文本

    现在的问题是,当拖动时,可拖动元素中的文本令人讨厌地被选中而没有用......

    这就是我们向元素添加draggable 和dragging 类的原因。这将消除这种不需要的行为,并添加一个移动光标,以显示该元素是可拖动的

    .draggable{
        cursor: move;
        position: fixed;
    }
    
    .draggable.dragging{
        user-select: none;
    }
    

    添加事件

    所以现在我们有了可拖动元素,有时我们需要调用各种事件。

    setup.ondraginit  // this is called when setting up the draggable
    setup.ondragstart // this is called when mouse is down on the element
    setup.ondragend   // this is called when mouse is released (after dragging)
    setup.ondrag      // this is called while the element is being dragged
    

    每个都将原始鼠标事件传递给特定的处理程序

    最后,这就是我们得到的……

    Element.prototype.drag = function( setup ){
    
        var setup = setup || {};
    
        var mousemove = function(e){ // document mousemove
    
            this.style.left = ( e.clientX - this.dragStartX ) + 'px';
            this.style.top  = ( e.clientY - this.dragStartY ) + 'px';
    
            setup.ondrag && setup.ondrag(e); // ondrag event
    
        }.bind(this);
    
        var mouseup = function(e){ // document mouseup
    
            document.removeEventListener('mousemove',mousemove);
            document.removeEventListener('mouseup',mouseup);
    
            handle.classList.remove('dragging');
    
            setup.ondragend && setup.ondragend(e); // ondragend event
    
        }.bind(this);
    
        var handle = setup.handle || this;
    
        handle.addEventListener('mousedown',function(e){ // element mousedown
    
            this.dragStartX = e.offsetX;
            this.dragStartY = e.offsetY;
    
            document.addEventListener('mousemove',mousemove);
            document.addEventListener('mouseup',mouseup);
    
            handle.classList.add('dragging');
    
            setup.ondragstart && setup.ondragstart(e); // ondragstart event
    
        }.bind(this)); 
    
        handle.classList.add('draggable');
    
        setup.ondraginit && setup.ondraginit(e); // ondraginit event
    
    }
    

    并使用它:

    var setup = {
       handle      : document.querySelector('.handle'),
       ondragstart : e => { console.log('drag has started!'); },
       ondrag      : e => { console.log('drag!'); },
       ondragend   : e => { console.log('drag has ended!'); }
    };
    
    document.querySelector('.box').drag(setup);
    

    注意e.target 是对我们可拖动元素的引用

    【讨论】:

    • 非常干净!考虑创建另一个 SO 帐户只是为了再次投票。 ;)
    【解决方案5】:

    这是制作以点击为中心的可拖动对象的另一种方法

    http://jsfiddle.net/pixelass/fDcZS/

    function endMove() {
        $(this).removeClass('movable');
    }
    
    function startMove() {
        $('.movable').on('mousemove', function(event) {
            var thisX = event.pageX - $(this).width() / 2,
                thisY = event.pageY - $(this).height() / 2;
    
            $('.movable').offset({
                left: thisX,
                top: thisY
            });
        });
    }
    $(document).ready(function() {
        $("#containerDiv").on('mousedown', function() {
            $(this).addClass('movable');
            startMove();
        }).on('mouseup', function() {
            $(this).removeClass('movable');
            endMove();
        });
    
    });
    

    CSS

    #containerDiv {
        background:#333;
        position:absolute;
        width:200px;
        height:100px;
    }
    

    【讨论】:

      【解决方案6】:

      像 jQueryUI 一样拖动:JsFiddle

      您可以从任意点拖动元素而无需奇怪的居中。

      $(document).ready(function() {
      
              var $body = $('body');
              var $target = null;
              var isDraggEnabled = false;
      
              $body.on("mousedown", "div", function(e) {
      
                  $this = $(this);
                  isDraggEnabled = $this.data("draggable");
      
                  if (isDraggEnabled) {
                      if(e.offsetX==undefined){
                          x = e.pageX-$(this).offset().left;
                          y = e.pageY-$(this).offset().top;
                      }else{
                          x = e.offsetX;
                          y = e.offsetY;
                      };
      
                      $this.addClass('draggable');
                      $body.addClass('noselect');
                      $target = $(e.target);
                  };
      
              });
      
               $body.on("mouseup", function(e) {
                  $target = null;
                  $body.find(".draggable").removeClass('draggable');
                  $body.removeClass('noselect');
              });
      
               $body.on("mousemove", function(e) {
                  if ($target) {
                      $target.offset({
                          top: e.pageY  - y,
                          left: e.pageX - x
                      });
                  };     
               });
      
          });
      

      【讨论】:

      • 有趣的结果。如果将其添加到 div,则可以将其所有子元素拖出,但如果单击并拖动实际 div 而不是子元素,则会移动所有内容。
      【解决方案7】:

      这是我的。 http://jsfiddle.net/pd1vojsL/

      一个div中的3个可拖动按钮,拖动受div约束。

      <div id="parent" class="parent">
          <button id="button1" class="button">Drag me</button>
          <button id="button2" class="button">Drag me</button>
          <button id="button3" class="button">Drag me</button>
      </div>
      <div id="log1"></div>
      <div id="log2"></div>
      

      需要 JQuery(仅):

      $(function() {
          $('.button').mousedown(function(e) {
              if(e.which===1) {
                  var button = $(this);
                  var parent_height = button.parent().innerHeight();
                  var top = parseInt(button.css('top')); //current top position
                  var original_ypos = button.css('top','').position().top; //original ypos (without top)
                  button.css({top:top+'px'}); //restore top pos
                  var drag_min_ypos = 0-original_ypos;
                  var drag_max_ypos = parent_height-original_ypos-button.outerHeight();
                  var drag_start_ypos = e.clientY;
                  $('#log1').text('mousedown top: '+top+', original_ypos: '+original_ypos);
                  $(window).on('mousemove',function(e) {
                      //Drag started
                      button.addClass('drag');
                      var new_top = top+(e.clientY-drag_start_ypos);
                      button.css({top:new_top+'px'});
                      if(new_top<drag_min_ypos) { button.css({top:drag_min_ypos+'px'}); }
                      if(new_top>drag_max_ypos) { button.css({top:drag_max_ypos+'px'}); }
                      $('#log2').text('mousemove min: '+drag_min_ypos+', max: '+drag_max_ypos+', new_top: '+new_top);
                      //Outdated code below (reason: drag contrained too early)
                      /*if(new_top>=drag_min_ypos&&new_top<=drag_max_ypos) {
                          button.css({top:new_top+'px'});
                      }*/
                  });
                  $(window).on('mouseup',function(e) {
                       if(e.which===1) {
                          //Drag finished
                          $('.button').removeClass('drag');
                          $(window).off('mouseup mousemove');
                          $('#log1').text('mouseup');
                          $('#log2').text('');
                       }
                  });
              }
          });
      });
      

      【讨论】:

      • 对我很有帮助。真的节省了我很多时间。
      【解决方案8】:

      我在上面看到的很复杂.....

      这里有一些代码可以参考。

      $("#box").on({
                      mousedown:function(e)
                      {
                        dragging = true;
                        dragX = e.clientX - $(this).position().left;
                        //To calculate the distance between the cursor pointer and box 
                        dragY = e.clientY - $(this).position().top;
                      },
                      mouseup:function(){dragging = false;},
                        //If not set this on/off,the move will continue forever
                      mousemove:function(e)
                      {
                        if(dragging)
                        $(this).offset({top:e.clientY-dragY,left:e.clientX-dragX});
      
                      }
                  })
      

      dragging,dragX,dragY 可以作为全局变量放置。

      这是一个关于这个问题的简单展示,但是这个方法有一些错误。

      如果您现在需要,这里是Example here.

      【讨论】:

        【解决方案9】:
        $(document).ready(function() {
            var $startAt = null;
        
            $(document.body).live("mousemove", function(e) {
                if ($startAt) {
                    $("#someDiv").offset({
                        top: e.pageY,
                        left: $("#someDiv").position().left-$startAt+e.pageX
                    });
                    $startAt = e.pageX; 
                }
            });
        
            $("#someDiv").live("mousedown", function (e) {$startAt = e.pageX;});
            $(document.body).live("mouseup", function (e) {$startAt = null;});
        });
        

        【讨论】:

          【解决方案10】:

          我有一个不使用任何 JQuery 的简单版本,它甚至很容易实现!

          // add 'draggable-object' as an attribute to your div element
          var dragDiv = document.querySelector("div[draggable-object]");
          // add the '-header' to the header element of the draggable div if you want the user to press a specific part of the element to drag it
          var dragDivHeader = document.querySelector("div[draggable-object-header]");
          
          // function for getting the mouse offset from the div position
          function getMouseOffset()
          {
              var e = window.event;
              
              var divX = parseInt(getComputedStyle(dragDiv).left);
              var divY = parseInt(getComputedStyle(dragDiv).top);
              
              return {
                  X: e.clientX - divX,
                  Y: e.clientY - divY,
              };
          }
          
          // variable for storing mouse offset from div element position
          var mouseOffset = null;
          
          // enable the mouse events, but on the document itself for easy dragging
          function enableMouseDrag()
          {
              document.onmouseup = disableMouseDrag;
              document.onmousemove = dragDivWithMouse;
              
              mouseOffset = getMouseOffset(); // get the mouse offset only when pressing down once
          }
          
          // drag div with mouse
          function dragDivWithMouse()
          {
              var e = window;
              
              // get the new x/y position of the draggable div element
              var newX = e.clientX - mouseOffset.X;
              var newY = e.clientY - mouseOffset.Y;
              
              // sets the new element position while also keeping it inside the document page without more lines of code
              dragDiv.style.left = Math.max(2, Math.min(newX, document.documentElement.clientWidth - dragDiv.offsetWidth - 2)) + "px";
              dragDiv.style.top = Math.max(2, Math.min(newY, document.documentElement.clientHeight - dragDiv.offsetHeight - 2)) + "px";
          }
          
          // disable the mouse events for the document itself
          function disableMouseDrag()
          {
              document.onmouseup = null;
              document.onmousemove = null;
          }
          
          // add the enableMouseDrag event callback to the div itself, or specify its header if you want
          dragDiv.onmousedown = enableMouseDrag;
          // dragDivHeader.onmousedown = enableMouseDrag;
          

          我希望这是一个简单可用的解决方案。

          【讨论】:

            【解决方案11】:

            这是我的简单版本。
            draggable 函数接受一个 jQuery 对象作为参数。

            
            /**
             * @param {jQuery} elem
             */
            function draggable(elem){
            
                elem.mousedown(function(evt){
                    var x = parseInt(this.style.left || 0) - evt.pageX;
                    var y = parseInt(this.style.top || 0) - evt.pageY;
            
                    elem.mousemove(function(evt){
                        elem.css('left', x + evt.pageX);
                        elem.css('top', y + evt.pageY);
                    });
                });
            
                elem.mouseup(off);
                elem.mouseleave(off);
            
                function off(){
                    elem.off("mousemove");
                }
            }
            
            

            【讨论】:

              【解决方案12】:

              这是一个完全不使用 jQuery 的实现 -
              http://thezillion.wordpress.com/2012/09/27/javascript-draggable-2-no-jquery

              将 JS 文件 (http://zillionhost.xtreemhost.com/tzdragg/tzdragg.js) 嵌入到您的 HTML 代码中,并放入以下代码 -

              <script>
              win.onload = function(){
               tzdragg.drag('elem1, elem2, ..... elemn');
               // ^ IDs of the draggable elements separated by a comma.
              }
              </script>
              

              而且代码也很容易学习。
              http://thezillion.wordpress.com/2012/08/29/javascript-draggable-no-jquery

              【讨论】:

              • 请注意,每次链接到您自己的网站/项目时,您都要求披露。
              猜你喜欢
              • 1970-01-01
              • 2017-04-18
              • 1970-01-01
              • 1970-01-01
              • 2012-04-02
              • 2013-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多