jQuery draggable이 페이지 스크롤 후 잘못된 위치에 도우미를 표시합니다.


79

개발중인 작업 계획 시스템에 jQuery 드래그 앤 드롭 가능을 사용 하고 있습니다. 사용자는 작업을 다른 날짜 또는 사용자로 끌어 놓은 다음 ajax 호출을 사용하여 데이터를 업데이트합니다.

메인 페이지를 아래로 스크롤 할 때를 제외하고는 모든 것이 잘 작동합니다 (작업은 브라우저 창 하단을 초과하는 큰 주간 플래너에 나타납니다). 여기에서 드래그 할 수있는 요소를 드래그하면 마우스 커서 위에 요소가 아래로 스크롤 한 것과 동일한 양의 픽셀이 나타납니다. 호버 상태는 여전히 잘 작동하고 기능은 작동하지만 제대로 표시되지 않습니다.

jQuery 1.6.0 및 jQuery UI 1.8.12를 사용하고 있습니다.

추가해야 할 오프셋 기능이 있다고 확신하지만 적용 할 위치 또는 더 나은 방법이 있는지 모르겠습니다. 내 .draggable()초기화 코드는 다음과 같습니다 .

$('.job').draggable({
  zIndex: 20,
  revert: 'invalid',
  helper: 'original',
  distance: 30,
  refreshPositions: true,
});

이 문제를 해결하기 위해 무엇을 할 수 있는지 아십니까?


당신은 몇 가지 작업 데모를 제공 할 수 있습니다
— jimy

@jimy 모든 것이 역동적이고 매우 안전하므로 완전히 새로운 예제를 작성해야합니다. 아무도 빨리 대답하지 않으면 그렇게 할 것입니다.
— Alex

드래그 가능하거나 상속받은 모든 CSS 속성을 게시 할 수 있습니까?
— DarthJDG 2011

2
아래에있는 내 대답에 따라 이것은 마침내 수정 된
— Patrick

답변:


107

이것은 관련 버그 보고서 일 수 있으며 꽤 오랫동안 사용되었습니다. http://bugs.jqueryui.com/ticket/3740

내가 테스트 한 모든 브라우저 (Chrome, FF4, IE9)에서 발생하는 것 같습니다. 이 문제를 해결할 수있는 몇 가지 방법이 있습니다.

1.position:absolute; 귀하의 CSS에서 사용하십시오 . 절대적으로 배치 된 요소는 영향을받지 않는 것 같습니다.

2. 부모 요소 (본문 인 경우 이벤트)가 overflow:auto;설정 되었는지 확인합니다 . 내 테스트에 따르면이 솔루션은 위치를 수정하지만 자동 스크롤 기능을 비활성화합니다. 여전히 마우스 휠이나 화살표 키를 사용하여 스크롤 할 수 있습니다.

3. 위의 버그 리포트에서 제안한 수정 사항을 수동으로 적용하고 다른 문제가 발생하는지 철저하게 테스트합니다.

4. 공식 수정을 기다립니다. 과거에 몇 차례 연기되었지만 jQuery UI 1.9로 예정되어 있습니다.

5. 모든 브라우저에서 발생한다고 확신하는 경우 이러한 해킹을 영향을받는 드래그 가능 항목의 이벤트에 넣어 계산을 수정할 수 있습니다. 하지만 테스트 할 다른 브라우저가 많으므로 최후의 수단으로 만 사용해야합니다.

$('.drag').draggable({
   scroll:true,
   start: function(){
      $(this).data("startingScrollTop",$(this).parent().scrollTop());
   },
   drag: function(event,ui){
      var st = parseInt($(this).data("startingScrollTop"));
      ui.position.top -= $(this).parent().scrollTop() - st;
   }
});

12
훌륭합니다. 감사합니다! (설정 오버플로 : 자동 즉시 고정 I 개별 테이블 셀에 스타일을 적용했다..
— 알렉스

2
jsfiddle.net/a2hzt/5 overflow-y : html 요소를 스크롤하면 파이어 폭스 에서도이 문제가 발생합니다 (크롬 작동). 아래로 스크롤하여 드래그 해보세요.
— digitalPBK

8
에 대한 ba-a-ack입니다 helper: "clone". bugs.jqueryui.com/ticket/9315 레벨 차단기 , 전공보다 한 단계 높았습니다 . tj.vantoll은 "1.10.3에 도입 된 6 개의 드래그 가능한 수정 사항이 의심 스러울 수 있습니다."라고 말합니다. 아직 가장 간단한 예 : jsfiddle.net/7AxXE
— Bob Stein

7
확인 됨,이 버그는 jQuery UI 1.10.3에 있지만 1.10.2에는 없습니다
— Bob Stein

2
문제가 jQuery UI 1.10.4 에도 존재하는 것 같습니다 . 지금은 1.10.2 를 고수하겠습니다 !
— lhan 2014 년

45

이 솔루션은 아무것도 위치를 조정하지 않고 작동합니다. 요소를 복제하고 절대 위치를 지정하기 만하면됩니다.

$(".sidebar_container").sortable({
  ..
  helper: function(event, ui){
    var $clone =  $(ui).clone();
    $clone .css('position','absolute');
    return $clone.get(0);
  },
  ...
});

도우미는 드래그 할 DOM 요소를 반환해야하는 함수일 수 있습니다.


+1 대단히 감사합니다. 이것은 정렬 가능으로 작동합니다 (비슷하지만 덜 우아한 것을 시도하려고했습니다). 하지만 $ j에 작은 오타가 있습니다! :)
— Iain Collins

4
나를 위해 : 형식 오류 : 드래그이 반환 오류가 전혀없는 작업을 수행 this.offsetParent [0] 정의되지 않는다
— ProblemsOfSumit

나는뿐만 아니라 UI ui.helper 생각
— 모하메드 Joraid

1
Sortable로 도와 주셔서 감사합니다
— BG BRUNO

1
이것은 나에게 적합한 유일한 대답이며 구현하기 가장 간단합니다. 훌륭한 솔루션
— Brett Gregson

11

이것은 나를 위해 일했습니다.

start: function (event, ui) {
   $(this).data("startingScrollTop",window.pageYOffset);
},
drag: function(event,ui){
   var st = parseInt($(this).data("startingScrollTop"));
   ui.position.top -= st;
},

내 문제를 해결"1.11.0"
— Зелёный

이것은 재미있는 해결책이지만 버그가있는 브라우저 (Chrome)에서만 작동합니다. 버그가없는 브라우저는 이제 버그가 있지만 반전됩니다. :)
— manu

참고 : 일부 JS-Parsers는이 솔루션을 사용할 때 "기수 누락"에 대해 불평 할 수 있습니다. 수정하려면 var st = parseInt ($ (this) .data ( "startingScrollTop")); var st = parseInt ($ (this) .data ( "startingScrollTop"), 10); (즉, 사용할 숫자 체계를 제공하십시오). 10이 기본값이지만 일부 구문 분석기는 이것이 존재해야 할 수도 있습니다 (예 : webpack)
— ripper17

7

다른 답변을 써서 죄송합니다. 위 답변의 솔루션 중 어느 것도 사용할 수 없으므로 다른 합리적인 솔루션을 찾기 전에 많은 인터넷 검색을 수행하고 많은 실망스러운 사소한 편집을 수행했습니다.

이 문제는 때마다 발생하는 것 같습니다 어떤 부모 요소가있다 position'상대'로 설정. 마크 업을 재구성하고 CSS를 변경해야했지만 모든 부모로부터이 속성을 제거함으로써 .sortable()모든 브라우저에서 제대로 작동 할 수있었습니다 .


여기 저도 마찬가지입니다. 어떤 부 position: relative;모든이 일이 발생합니다.
— wojtiku 2013

완전히 동의합니다! 나에게있어서 그것은 단지 position: relative;제거되어야 하는 본문의 인라인 스타일이었다 .. 드래그 가능과 본문 사이의 부모 요소는 여기서 문제를 일으키지 않는 것 같다 ..
— con

1
감사합니다. 왜 사람들이이 시대에 Dragula를 사용하지 않는지-감사합니다!
— Dominic

정말 고맙습니다! 부모를 갖는 위치의 부모 : 상대는 나를 위해 그것을 발생
— wjk2a1

7

이 버그는 매우 자주 발생하며 매번 다른 솔루션이있는 것 같습니다. 위의 어느 것도 또는 인터넷에서 찾은 다른 어떤 것도 작동하지 않았습니다. jQuery 1.9.1 및 Jquery UI 1.10.3을 사용하고 있습니다. 이것이 내가 수정 한 방법입니다.

$(".dragme").draggable({
  appendTo: "body",
  helper: "clone",
  scroll: false,
  cursorAt: {left: 5, top: 5},
  start: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  },
  drag: function(event, ui) {
    if(! $.browser.chrome) ui.position.top -= $(window).scrollTop();
  }
});

FF, IE, Chrome에서 작동하지만 다른 브라우저에서는 아직 테스트하지 않았습니다.


1
이것은 ui.position.top 대신 ui.offset.top을 사용해야한다는 점을 제외하면 저에게 효과적이었습니다.
— c.dunlap

5

오버플로를 삭제합니다.

html {overflow-y: scroll; background: #fff;}

그리고 완벽하게 작동합니다!


5

이 버그는 http://bugs.jqueryui.com/ticket/6817 로 옮겨졌으며 , 약 5 일 전 (2013 년 12 월 16 일 또는 그 전후)에 마침내 수정 된 것으로 보입니다. 현재 권장 사항은 http://code.jquery.com/ui/jquery-ui-git.js 의 최신 개발 빌드를 사용 하거나이 수정 사항이 포함 된 버전 1.10.4를 기다리는 것입니다 .

편집 : 이 수정 사항은 이제 버전 1.11까지 삭제되지 않는 http://bugs.jqueryui.com/ticket/9315의 일부일 수 있습니다 . 위의 링크 된 소스 제어 버전의 jQuery를 사용하면 저와 @Scott Alexander (아래 주석)의 문제가 해결되는 것 같습니다.


나는 1.10.4를 사용하고 있으며 버그는 여전히 존재하며 해당 링크를 사용했지만 모두 잘 작동합니다.
— Scott Alexander

@ScottAlexander 수정 사항이 내가 생각한 것과 다른 티켓에 첨부되었을 수 있습니다. 나는 그것을 기반으로 내 대답을 편집했습니다. 감사!
— Patrick

4

이 버그가 너무 오래 수정되지 않았어야했다는 것이 놀랍습니다. 나에게는 Safari와 Chrome (예 : 웹킷 브라우저)에서는 문제가되지만 IE7 / 8 / 9 나 Firefox에서는 문제가되지 않으며 모두 잘 작동합니다.

! important 여부에 관계없이 절대 또는 고정 설정이 도움이되지 않았으므로 결국 드래그 핸들러 함수에 한 줄을 추가했습니다.

ui.position.top += $( 'body' ).scrollTop();

나는 그 라인을 웹킷에 특화시킬 필요가있을 것으로 예상했지만 호기심이 모든 곳에서 잘 작동했습니다. (곧 '아니요, 실제로 다른 모든 브라우저를 엉망으로 만들었습니다'라고 말하는 댓글을 기대하십시오.)


1
이것은 작동하지만 드래그하는 동안 스크롤하면 여전히 y 위치가 이동합니다. DarthJDG의 솔루션 번호 5는 드래그하는 동안 스크롤 할 때도 작동합니다.
— mirelon 2013 년

3

내가 한 것은 :

$("#btnPageBreak").draggable(
        {
          appendTo: 'body',
          helper: function(event) {
            return '<div id="pageBreakHelper"><img  id="page-break-img"  src="page_break_cursor_red.png" /></div>';
          },
          start: function(event, ui) {
          },
          stop: function(event, ui) {
          },
          drag: function(event,ui){
            ui.helper.offset(ui.position);
         }
        });

1

이 방법이 모든 경우에 효과가 있을지 확신 할 수 없지만이 해결 방법은 내가 테스트해야하는 모든 다양한 상황 (그리고 여기 및 다른 곳에서 제공된 이전 제안 된 솔루션이 모두 실패한 경우)에서 나를 위해 작동했습니다.

(function($){
$.ui.draggable.prototype._getRelativeOffset = function()
{
    if(this.cssPosition == "relative") {
        var p = this.element.position();
        return {
            top: p.top - (parseInt(this.helper.css("top"),10) || 0)/* + this.scrollParent.scrollTop()*/,
            left: p.left - (parseInt(this.helper.css("left"),10) || 0)/* + this.scrollParent.scrollLeft()*/
        };
    } else {
        return { top: 0, left: 0 };
    }
};
}(jQuery));

(저는 jQuery.ui 트래커에 제출하여 그들이 그것에 대해 어떻게 생각하는지 확인했습니다. 4 년 된 버그가 마침내 수정 될 수 있다면 멋질 것입니다 : /)


1

Firefox 21.0에서 JQuery draggable을 사용하고 있는데 같은 문제가 있습니다. 커서는 도우미 이미지에서 1 인치 위에 있습니다. 나는 이것이 아직 해결되지 않은 Jquery 자체의 문제라고 생각합니다. draggable의 "cursorAt"속성을 사용하는이 문제에 대한 해결 방법을 찾았습니다. 다음과 같이 사용했지만 요구 사항에 따라 변경할 수 있습니다.

$('.dragme').draggable({
helper: 'clone',    
cursor: 'move',    
cursorAt: {left: 50, top: 80}
});

참고 : 이는 모든 브라우저에 적용되므로이 코드를 사용한 후 모든 브라우저에서 페이지를 확인하여 올바른 왼쪽 및 상단 위치를 찾으십시오.


1

이것이 제가 읽은 모든 것을 문제에 적용한 후 저에게 효과적이었습니다.

$(this).draggable({
  ...
  start: function (event, ui) {
    $(this).data("scrollposTop", $('#elementThatScrolls').scrollTop();
    $(this).data("scrollposLeft", $('#elementThatScrolls').scrollLeft();
  },
  drag: function (event, ui) {
    ui.position.top += $('#elementThatScrolls').scrollTop();
    ui.position.left += $('#elementThatScrolls').scrollLeft();
  },
  ...
}); 

* elementThatScrolls는 overflow : auto가있는 상위 또는 조상입니다.

스크롤링 요소의 위치를 ​​조정하고 이동 / 드래그 할 때마다 도우미의 위치에 추가합니다.

내가 이것에 많은 시간을 낭비했기 때문에 누군가에게 도움이되기를 바랍니다.


1

이것은 부모에서 position : absolute를 사용할 필요없이 해결 방법을 수행하는 것 같습니다. :)

$("body").draggable({
     drag: function(event, ui) { 
         return false; 
     } 
});

감사! 이것은 나를 위해 일한 유일한 것입니다. (문제를 이해하고 있는지 모르겠습니다. 내 문제는 드래그가 상단의 스크롤바에서 시작될 때 드래그, 드래그 스크롤링이 잘 작동한다는 것입니다. 스크롤바가 더 낮게 시작되면 오프셋 문제가 발생합니다.)
— John Smith

1

display: inline-block 드래그 한 항목에 추가하는 것과 동일한 문제를 해결했습니다.

추가 position: relative가 작동하지 않았습니다 (jQuery position: absolute는 드래그 시작시 재정의 )

사용 된 jQuery 버전 :

  • jQuery-1.7.2
  • jQuery UI-1.11.4

position: relative더 높은 수준의 컨테이너 요소로 이동하면 작동했을 수 있습니다. 나는 그것이 지금 도움이되지 않는다는 것을 알고 있지만 단지 참고 용이고 어쩌면 미래의 문제가있는 개발자를위한 것일 수도 있습니다.
— gdibble

1

나는 똑같은 문제가 있었고이 모든 것이 위치가 고정 된 부트 스트랩 navbar "navbar-fixed-top"클래스로 <body>인해 <html>상단 보다 60px 아래 로 이동한다는 것을 발견했습니다 . 따라서 내 사이트에서 드래그 가능한 양식을 이동할 때 커서가 양식 위에 60px로 나타났습니다.

Chrome 디버깅 도구의 Elements 인터페이스에서 <body>태그를 클릭 하면 상단과 본문 사이에 간격이 있음을 알 수 있습니다.

응용 프로그램 전체에서이 navbar를 사용하고 있기 때문에 각 양식에 대해 (DarthJDG의 절차에 따라) 드래그하기 위해 초기화 호출을 수정하고 싶지 않았습니다. 나는 드래그 가능한 위젯을 이런 방식으로 확장하고 드래그 가능한 초기화에 yOffset을 추가하기로 결정했습니다.

(function($) {
  $.widget("my-ui.draggable", $.ui.draggable, {
    _mouseDrag: function(event, noPropagation) {

      //Compute the helpers position
      this.position = this._generatePosition(event);
      this.positionAbs = this._convertPositionTo("absolute");

      //Call plugins and callbacks and use the resulting position if something is returned
      if (!noPropagation) {
        var ui = this._uiHash();
        if(this._trigger('drag', event, ui) === false) {
          this._mouseUp({});
          return false;
        }
        this.position = ui.position;
      }
      // Modification here we add yoffset in options and calculation
      var yOffset = ("yOffset" in this.options) ? this.options.yOffset : 0;

      if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
      if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top-yOffset+'px';
      if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);

      return false;
    }
  });
})(jQuery);

이제 부트 스트랩 navbar를 사용하여 사이트에서 드래그 가능한 요소 / 양식을 초기화 할 때 :

// Make the edit forms draggable
$("#org_account_pop").draggable({handle:" .drag_handle", yOffset: 60});

물론 자신의 사이트에 따라 올바른 yOffset을 결정하기 위해 실험해야합니다.

어쨌든 나에게 올바른 방향을 알려준 DarthJDG에게 감사드립니다. 건배!


0

나는 jQueryUi의 드래그를 사용하여 종료하고 더 나은 플러그인이라고 사용하는 이동 jquery.even.drag을 jQueryUI가 가진 모든 쓰레기없이 훨씬 작은 코드 크기 인 .

위치가있는 컨테이너 내부에서이 플러그인을 사용하여 데모 페이지를 만들었습니다.

데모

이 문제가 크기 때문에 누군가에게 도움이되기를 바랍니다.


0

Windows 8에서 실행되는 특정 IE 10에서만 비슷한 문제가 발생했습니다. 다른 모든 브라우저는 정상적으로 작동했습니다. cursorAt : {top : 0}을 제거하면 문제가 해결되었습니다.


0

여기에서 jQuery 업데이트를 포함하여 다양한 답변을 시도한 결과 이것이 저에게 효과적이라는 것을 알았습니다. 나는 이것을 최신 크롬과 IE에서 테스트했습니다. UI 레이아웃에 따라 다른 솔루션에 문제가 될 것 같습니다.

$('{selector}').draggable({
    start: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    },
    drag: function(event, ui) {
        ui.position.top -= $(document).scrollTop();
    }
});

0

커서 위치를 취하지 않는 이유는 무엇입니까? 정렬 가능한 플러그인을 사용 중이며 다음 코드로 수정합니다.

sort: function(e, ui) {
    $(".ui-sortable-handle.ui-sortable-helper").css({'top':e.pageY});
}

0

으로 appendTo: "body'위치를 설정하고 사용하십시오 cursorAt. 이것은 나에게 잘 작동합니다.

페이지를 스크롤 한 후에도 마우스 커서를 따라가는 아이콘의 예

$('.js-tire').draggable
      tolerance: 'fit',
      appendTo: 'body',
      cursor: 'move',
      cursorAt:
        top: 15,
        left: 18
      helper: (event) ->
        $('<div class="tire-icon"></div>').append($('<img src="/images/tyre_32_32.png" />'))
      start: (event, ui) ->
        if $(event.target).hasClass 'in-use'
          $('.js-send-to-maintenance-box').addClass 'is-highlighted'
        else
          $('.ui-droppable').addClass 'is-highlighted'
      stop: (event, ui) ->
        $('.ui-droppable')
          .removeClass 'is-highlighted'
          .removeClass 'is-dragover'

0

나는 상단에 끈적한 내비게이션을 사용하고 있으며 그것이 다른 모든 사람들이 겪고있는 것처럼 보이는 스크롤 문제의 원인이라고 생각했습니다. 나는 cursorAt으로 다른 모든 사람의 아이디어를 시도했고, 격리를 시도했지만 CSS에서 내 html 오버플로를 설정하지 않는 한 아무것도 작동하지 않았습니다! 약간의 CSS가 모든 것을 망칠 수있는 미친 짓입니다. 이것은 내가 한 일이며 매력처럼 작동합니다.

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.