jQuery có thể kéo hiển thị trình trợ giúp ở sai vị trí sau khi trang được cuộn


79

Tôi đang sử dụng jQuery có thể kéodroppable cho một hệ thống kế hoạch hoạt động tôi đang phát triển. Người dùng kéo công việc sang một ngày hoặc người dùng khác và sau đó dữ liệu được cập nhật bằng lệnh gọi ajax.

Mọi thứ đều hoạt động tốt, ngoại trừ khi tôi cuộn xuống trang chính (Công việc xuất hiện trên bảng kế hoạch tuần lớn vượt quá cuối cửa sổ trình duyệt của tôi). Nếu tôi thử và kéo một phần tử có thể kéo vào đây, phần tử sẽ xuất hiện phía trên con trỏ chuột của tôi với cùng số lượng pixel như tôi đã cuộn xuống .. Trạng thái di chuột vẫn hoạt động tốt và chức năng hoạt động nhưng có vẻ không ổn.

Tôi đang sử dụng jQuery 1.6.0 và jQuery UI 1.8.12.

Tôi chắc chắn rằng có một hàm bù đắp mà tôi cần thêm nhưng tôi không biết áp dụng nó ở đâu, hoặc nếu có cách nào tốt hơn. Đây là .draggable()mã khởi tạo của tôi :

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

Bất kỳ ý tưởng nào tôi có thể làm gì để khắc phục điều này?


bạn có thể cung cấp một số bản demo hoạt động không
jimy

@jimy tất cả đều năng động và rất an toàn, vì vậy tôi phải viết một ví dụ hoàn toàn mới; Tôi sẽ làm nếu không ai có câu trả lời nhanh càng sớm càng tốt.
Alex

Bạn có thể đăng tất cả các thuộc tính css mà draggable của bạn có hoặc kế thừa không?
DarthJDG

2
Theo câu trả lời của tôi ở phía dưới, điều này dường như cuối cùng đã
Patrick

Câu trả lời:


107

Đây có thể là một báo cáo lỗi liên quan, nó đã xuất hiện khá lâu rồi: http://bugs.jqueryui.com/ticket/3740

Nó dường như xảy ra trên mọi trình duyệt tôi đã thử nghiệm (Chrome, FF4, IE9). Có một số cách bạn có thể giải quyết vấn đề này:

1. Sử dụng position:absolute;trong css của bạn. Các yếu tố được định vị tuyệt đối dường như không bị ảnh hưởng.

2. Đảm bảo rằng phần tử cha (sự kiện nếu là phần thân) đã overflow:auto;được thiết lập. Thử nghiệm của tôi cho thấy rằng giải pháp này sửa chữa vị trí, nhưng nó vô hiệu hóa chức năng tự động cuộn. Bạn vẫn có thể cuộn bằng con lăn chuột hoặc các phím mũi tên.

3. Áp dụng bản sửa lỗi được đề xuất trong báo cáo lỗi ở trên theo cách thủ công và kiểm tra kỹ lưỡng nếu nó gây ra các sự cố khác.

4. Chờ bản sửa lỗi chính thức. Nó được lên lịch cho jQuery UI 1.9, mặc dù nó đã bị hoãn một vài lần trong quá khứ.

5. Nếu bạn tự tin rằng nó xảy ra trên mọi trình duyệt, bạn có thể đặt các hack này vào các sự kiện của người kéo bị ảnh hưởng để sửa các phép tính. Tuy nhiên, có rất nhiều trình duyệt khác nhau để kiểm tra, vì vậy nó chỉ nên được sử dụng như một phương sách cuối cùng:

$('.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
Thật tuyệt vời, cảm ơn bạn! (Phần tràn cài đặt: tự động sửa lỗi này ngay lập tức. Tôi đã áp dụng kiểu cho các ô trong bảng riêng lẻ.
Alex

2
jsfiddle.net/a2hzt/5 tràn-y: cuộn trên phần tử html cũng tạo ra vấn đề này trên firefox (chrome hoạt động), chỉ cần cuộn xuống và thử kéo.
digitalPBK

8
Đó là ba-a-ack, cho helper: "clone". bug.jqueryui.com/ticket/9315 Trình chặn cấp độ , một cấp độ lớn hơn. tj.vantoll cho biết "6 bản sửa lỗi có thể kéo được cập nhật trong 1.10.3 có thể bị nghi ngờ." Ví dụ đơn giản nhất được nêu ra: jsfiddle.net/7AxXE
Bob Stein

7
Đã xác nhận, lỗi này nằm trong giao diện người dùng jQuery 1.10.3 chứ không phải 1.10.2
Bob Stein

2
Có vẻ như sự cố cũng tồn tại trong jQuery UI 1.10.4 . Tôi sẽ chỉ bám vào 1.10.2 ngay bây giờ!
lhan

45

Giải pháp này hoạt động mà không cần điều chỉnh vị trí của bất kỳ thứ gì, bạn chỉ cần sao chép phần tử và làm cho nó được định vị tuyệt đối.

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

Trình trợ giúp có thể là một hàm cần trả về phần tử DOM để kéo theo.


+1 Cảm ơn rất nhiều, điều này phù hợp với tôi với sắp xếp (Tôi đã định thử một cái gì đó tương tự nhưng kém thanh lịch hơn). Tuy nhiên, bạn có một lỗi đánh máy nhỏ với $ j! :)
Iain Collins

4
Đối với tôi: kéo không làm việc ở tất cả với điều này và trả về lỗi: Lỗi Loại: this.offsetParent [0] là undefined
ProblemsOfSumit

Tôi nghĩ đó là ui.helper không chỉ ui
Mohammed Joraid

1
Cảm ơn bạn đã giúp tôi với Sortable
BG BRUNO

1
Đây là câu trả lời duy nhất phù hợp với tôi và nó là câu trả lời đơn giản nhất để thực hiện. Giải pháp tuyệt vời
Brett Gregson

11

Điều này đã làm việc cho tôi:

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

khắc phục sự cố của tôi,"1.11.0"
Зелёный

Đó là một giải pháp thú vị, nhưng Nó sẽ chỉ hoạt động trên các trình duyệt có lỗi (Chrome). Các trình duyệt không có lỗi bây giờ sẽ có nhưng bị đảo ngược :)
manu

Lưu ý: một số JS-Parser có thể phàn nàn về việc "thiếu cơ số" khi sử dụng giải pháp này. Để khắc phục, hãy thay thế var st = parseInt ($ (this) .data ("startedScrollTop")); với var st = parseInt ($ (this) .data ("startScrollTop"), 10); (tức là cung cấp hệ thống chữ số sẽ được sử dụng). 10 là mặc định, nhưng một số phân tích cú pháp có thể yêu cầu này phải có mặt Nontheless (ví dụ webpack)
ripper17

7

Xin lỗi vì đã viết câu trả lời khác. Vì không có giải pháp nào trong câu trả lời trên có thể được sử dụng bởi tôi, tôi đã thực hiện rất nhiều Google Googling và thực hiện nhiều chỉnh sửa nhỏ khó chịu trước khi tìm ra giải pháp hợp lý khác.

Sự cố này dường như xảy ra bất cứ khi nào bất kỳ phần tử cha nào positionđược đặt thành 'tương đối'. Tôi đã phải cải tổ lại đánh dấu và thay đổi CSS của mình nhưng bằng cách xóa thuộc tính này khỏi tất cả các trang gốc, tôi có thể .sortable()hoạt động bình thường trong tất cả các trình duyệt.


Ở đây cũng vậy. Bất kỳ position: relative;trong bất kỳ cha mẹ nào gây ra điều này xảy ra.
wojtiku

hoàn toàn đồng ý! Đối với tôi, đó chỉ là một phong cách nội tuyến trong phần thân position: relative;mà phải được loại bỏ .. các yếu tố chính giữa phần có thể kéo và phần thân dường như không tạo ra vấn đề gì ở đây ..
con

1
omg đó là cảm ơn, garrr tại sao mọi người không sử dụng Dragula trong thời đại ngày nay - cảm ơn!
Dominic

Cảm ơn bạn rất nhiều! Mẹ của cha mẹ có position: relative gây ra nó cho tôi
wjk2a1

7

Có vẻ như lỗi này xuất hiện rất thường xuyên và mỗi lần có một giải pháp khác nhau. Không có cách nào ở trên hoặc bất kỳ thứ gì khác mà tôi tìm thấy trên internet hoạt động. Tôi đang sử dụng jQuery 1.9.1 và Jquery UI 1.10.3. Đây là cách tôi sửa nó:

$(".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();
  }
});

Hoạt động trên FF, IE, Chrome, tôi chưa thử nghiệm nó trên các trình duyệt khác.


1
này làm việc cho tôi, ngoại trừ tôi đã phải sử dụng ui.offset.top thay vì ui.position.top
c.dunlap

5

Tôi xóa phần tràn:

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

Và nó hoạt động hoàn hảo!


5

Lỗi này đã được chuyển đến http://bugs.jqueryui.com/ticket/6817 và khoảng 5 ngày trước (ngày 16 tháng 12 năm 2013 trở đi) dường như cuối cùng đã được sửa. Đề xuất ngay bây giờ là sử dụng bản dựng phát triển mới nhất từ http://code.jquery.com/ui/jquery-ui-git.js hoặc đợi phiên bản 1.10.4 sẽ có bản sửa lỗi này .

Chỉnh sửa: Có vẻ như bản sửa lỗi này hiện có thể là một phần của http://bugs.jqueryui.com/ticket/9315. Bản sửa lỗi này sẽ không được lên lịch cho đến phiên bản 1.11. Sử dụng phiên bản kiểm soát nguồn được liên kết ở trên của jQuery dường như khắc phục được sự cố cho tôi và @Scott Alexander (nhận xét bên dưới).


Tôi đang sử dụng 1.10.4 và lỗi vẫn còn đó, mặc dù đã sử dụng liên kết đó và tất cả đều hoạt động tốt.
Scott Alexander

@ScottAlexander Bản sửa lỗi có thể đã được đính kèm với một vé khác với tôi nghĩ. Tôi đã chỉnh sửa câu trả lời của mình dựa trên điều đó. Cảm ơn!
Patrick

4

Có vẻ như đáng chú ý là lỗi này đã không được sửa chữa lâu như vậy. Đối với tôi, đó là sự cố trên Safari và Chrome (tức là các trình duyệt webkit) nhưng không phải trên IE7 / 8/9 cũng như trên Firefox, tất cả đều hoạt động tốt.

Tôi thấy rằng cài đặt tuyệt đối hoặc cố định, có hoặc không! Important, không giúp ích được gì nên cuối cùng tôi đã thêm một dòng vào chức năng trình xử lý kéo của mình:

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

Tôi đã mong đợi cần phải làm cho webkit dòng đó cụ thể nhưng thật kỳ lạ, nó hoạt động tốt ở mọi nơi. (Mong nhận xét từ tôi sớm nói rằng 'ờ không, thực ra nó đã làm rối tung tất cả các trình duyệt khác'.)


1
Điều này hoạt động, nhưng khi bạn cuộn trong khi kéo, nó vẫn dịch chuyển vị trí y. Giải pháp số 5 của DarthJDG cũng hoạt động khi cuộn trong khi kéo.
mirelon

3

những gì tôi đã làm là:

$("#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

Tôi không hoàn toàn chắc chắn rằng cách này sẽ hoạt động trong mọi trường hợp nhưng cách giải quyết này mà tôi đã thực hiện phù hợp với tôi trong tất cả các tình huống khác nhau mà tôi phải thử nghiệm (và trong đó các giải pháp được đề xuất trước đó được đưa ra ở đây và những nơi khác đều thất bại)

(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));

(Tôi đã gửi nó cho trình theo dõi jQuery.ui để xem họ nghĩ gì về nó .. sẽ rất tuyệt nếu lỗi cũ 4 năm đó cuối cùng có thể được sửa chữa: /)


1

Tôi đang sử dụng JQuery có thể kéo trên Firefox 21.0 và tôi đang gặp sự cố tương tự. Con trỏ ở trên một inch trên hình ảnh trợ giúp. Tôi nghĩ rằng đây là một vấn đề trong chính Jquery vẫn chưa được giải quyết. Tôi đã tìm thấy một giải pháp cho vấn đề này, đó là sử dụng thuộc tính "cursorAt" của có thể kéo. Tôi đã sử dụng nó như sau, nhưng người ta có thể thay đổi điều này theo yêu cầu của nó.

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

Lưu ý: Điều này sẽ áp dụng cho tất cả các trình duyệt, vì vậy sau khi sử dụng mã này, hãy kiểm tra trang của bạn trong tất cả các trình duyệt để có đúng vị trí bên trái và trên cùng.


1

Đây là những gì đã làm việc cho tôi, sau khi điều chỉnh mọi thứ tôi đã đọc về vấn đề này.

$(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 là cha mẹ hoặc tổ tiên của tràn: auto;

Tính toán vị trí của phần tử cuộn và thêm vào vị trí của phần tử trợ giúp mỗi khi nó được di chuyển / kéo.

Hy vọng điều đó sẽ giúp ai đó, vì tôi đã lãng phí thời gian quan trọng vào việc này.


1

Điều này dường như thực hiện giải pháp thay thế mà không cần sử dụng vị trí: tuyệt đối trong cha mẹ :)

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

Cảm ơn! đây là điều duy nhất làm việc cho tôi. (Tôi không chắc mình hiểu vấn đề .. vấn đề của tôi là kéo, kéo cuộn hoạt động tốt khi quá trình kéo bắt đầu với thanh cuộn ở trên cùng. Nếu thanh cuộn bắt đầu thấp hơn thì tôi gặp sự cố bù trừ)
John Smith

1

Tôi đã cố gắng khắc phục sự cố tương tự bằng cách thêm display: inline-block vào các mục được kéo

Việc thêm position: relativeKHÔNG hoạt động đối với tôi (jQuery ghi đè nó khi position: absolutebắt đầu kéo)

Các phiên bản jQuery đã sử dụng:

  • jQuery - 1.7.2
  • jQuery UI - 1.11.4

position: relativecó thể đã hoạt động nếu bạn chuyển nó sang phần tử vùng chứa cấp cao hơn. Tôi biết bây giờ nó không giúp được gì, nhưng chỉ để tham khảo và có thể cho một nhà phát triển gặp khó khăn trong tương lai.
gdibble

1

Tôi gặp vấn đề tương tự và nhận thấy rằng tất cả điều này là do lớp bootstrap navbar "navbar-fixed-top" có vị trí cần cố định, di chuyển xuống <body>thấp hơn 60px so với <html>trên cùng của tôi. Vì vậy, khi tôi di chuyển các biểu mẫu có thể kéo trong trang web của mình, con trỏ xuất hiện 60px trên đầu biểu mẫu.

Bạn có thể thấy rằng trong công cụ gỡ lỗi của Chrome, trong giao diện Elements, nhấp vào <body>thẻ và bạn sẽ thấy khoảng cách giữa phần trên và phần thân.

Vì tôi đang sử dụng thanh điều hướng này trên tất cả các ứng dụng của mình và không muốn sửa đổi lệnh gọi đang khởi tạo để kéo (theo quy trình của DarthJDG) cho mỗi biểu mẫu. Tôi quyết định mở rộng tiện ích có thể kéo theo cách này và chỉ cần thêm một yOffset trong lần khởi tạo có thể kéo của mình.

(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);

Bây giờ khi tôi khởi tạo phần tử / biểu mẫu có thể kéo trong một trang web bằng bootstrap navbar:

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

Tất nhiên, bạn sẽ phải thử nghiệm để xác định yOffset phù hợp theo trang web của riêng bạn.

Dù sao cũng cảm ơn DarthJDG người đã chỉ cho tôi hướng đi đúng đắn. Chúc mừng!


0

Tôi đã bỏ sử dụng jQueryUi có thể kéo và chuyển sang sử dụng một plugin tốt hơn có tên là jquery.even.drag , kích thước mã nhỏ hơn nhiều, mà không có tất cả jQueryUI crap.

Tôi đã tạo một trang demo bằng cách sử dụng plugin này bên trong một vùng chứa có vị trí: fixed

Bản giới thiệu

Hy vọng điều này sẽ giúp ai đó, bởi vì vấn đề này là LỚN.


0

Tôi gặp sự cố tương tự, chỉ với IE 10 cụ thể đang chạy trên Windows 8. Tất cả các trình duyệt khác đều hoạt động tốt. Loại bỏ cursorAt: {top: 0} đã giải quyết được vấn đề.


0

Tôi đã thử các câu trả lời khác nhau ở đây, bao gồm cả cập nhật jQuery và nhận thấy rằng điều này phù hợp với tôi. Tôi đã thử nghiệm điều này trên chrome và IE mới nhất. Tôi đoán đây sẽ là một vấn đề với các giải pháp khác nhau tùy thuộc vào bố cục giao diện người dùng của bạn.

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

0

Tại sao không lấy vị trí con trỏ? tôi đang sử dụng plugin có thể sắp xếp và tôi sửa nó bằng mã này:

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

0

Sử dụng appendTo: "body'và đặt vị trí với cursorAt. Điều này làm tốt hình thức tôi.

Ví dụ về biểu tượng của tôi theo sau con trỏ chuột ngay cả sau khi cuộn trang

$('.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

Tôi đang sử dụng một điều hướng dính ở trên cùng và nghĩ rằng đó là nguyên nhân gây ra sự cố cuộn mà mọi người khác dường như đang gặp phải. Tôi đã thử ý tưởng của mọi người khác với cursorAt, tôi đã thử ngăn chặn và không có gì hiệu quả NGOẠI TRỪ việc bỏ đặt tràn html của tôi trong CSS! Thật điên rồ làm sao một chút CSS sẽ làm mọi thứ trở nên rối ren. Đây là những gì tôi đã làm và nó hoạt động như một sự quyến rũ:

html {
  overflow-x: unset;
}

body {
  overflow-x: hidden;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.