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.