web-dev-qa-db-ja.com

jQueryの並べ替え可能なリスト-並べ替え時にスクロールバーがジャンプする

私はデモを作成しました: http://Pastebin.me/584b9a86d715c9ba85b7bebf0375e237

スクロールバーが一番下にあり、アイテムをドラッグして並べ替えると、スクロールバーがジャンプします。 FF、Safari、Chrome、およびIE(少なくともIE8)でこれを行うようです。

私のMacのFirefoxでは、スクロールバーが一番下にあるときにジャンプアップしますが、リスト全体にニースフラッシュも追加します。リストを上にスクロールすると、リスト全体が正しく点滅します。何がスクロールアップを引き起こしているのかを理解すれば(そしてそれを止めることができれば)、点滅も止まると思います。

私はそれがそのように跳ね上がるのが好きではありませんb/c私はそれが耳障りで混乱していると思います。これはちょっとした問題だと思いますが、できれば修正したいと思います。

それで、それが上にスクロールするのを防ぐ方法はありますか?あるいは、何が原因で上にスクロールしますか?

ありがとう

26
rfadams

問題は非常に単純です。

まず、シナリオを設定しましょう。並べ替え可能な要素のリストがあります。ページは画面よりも高いため、スクロールバーがあり、ページは一番下にあり、スクロールバーは一番下にあります。

問題は、要素をドラッグしてjQueryがそれをdomから削除し、プレースホルダーを追加することです。速度を落としましょう。最初に要素が削除されます。リストが短くなり、ページが短くなり、スクロールバーが短くなります。次に、プレースホルダーが追加され、ページが長くなり、スロールバーが長くなります(ただし、ウィンドウは下にスクロールしないため、スクロールバーが上にジャンプしたように見えます)。

これに対抗するために私が見つけた最善の方法は、並べ替え可能なリストの高さが静的であることを確認することです。そのため、要素を削除しても要素が短くなることはありません。これを行う1つの方法は

create:function(){
    jQuery(this).height(jQuery(this).height());
}

上記は、ソート可能なリストの作成時に呼び出され、その高さを現在の高さに静的に設定します。

並べ替え可能な要素の1つに画像がある場合、タグのサイズを事前に定義しない限り、上記のコードは機能しません。理由は、height()が呼び出されて設定されると、画像が入力される前に計算されるためです。寸法がない場合、画像はスペースを占めません。画像が読み込まれると、スペースを占有します。

寸法を定義する必要があるのを回避する方法は次のとおりです。内の画像が読み込まれることが検出されるたびに、リストの高さのサイズを変更するだけです。

create:function(){
    var list=this;
    jQuery(list).find('img').load(function(){
        jQuery(list).height(jQuery(list).height());
    });
}

最終版:

jQuery(document).ready(function(){  
    jQuery("div#todoList").sortable({
        handle:'img.moveHandle',
        opacity: 0.6,
        cursor: 'move',
        tolerance: 'pointer',
        forcePlaceholderSize: true,
        update:function(){
            jQuery("body").css('cursor','progress');
            var order = jQuery(this).sortable('serialize');
            jQuery.post("/ajax.php?do=sort&"+order,function(data){jQuery("body").css('cursor','default');});
        },
        create:function(){
            var list=this;
            var resize=function(){
                jQuery(list).css("height","auto");
                jQuery(list).height(jQuery(list).height());
            };
            jQuery(list).height(jQuery(list).height());
            jQuery(list).find('img').load(resize).error(resize);
        }
    });
});
46
Carl M. Gregory

Divコンテナとdiv要素を使用してコンテナの高さを設定しても同じ問題が発生しましたが、含まれているdivでoverflow:autocssプロパティを明示的に設定すると問題が修正されました。ただし、Chromeでのみテストされています。

21
petrocket

私もこの問題を経験しました。これは、リストがページの長さを決定するときに発生します。並べ替えを開始すると、リストの高さが一瞬変化し、ページがジャンプします。これは奇妙ですが、この問題に対する非常に機能的な解決策です。

$('ul').height($('ul').height());
13
Jonathan

カール・M・グレゴリーはこの問題を完璧に説明していますが、彼の解決策は不必要に複雑だと思います。

リストの高さを固定値に設定すると問題は修正されますが、リストの作成時に設定するのは時期尚早です。 .mousedown()関数を使用して、並べ替えを開始する直前の高さを設定できます。この時点で、潜在的な画像はすでに読み込まれているため、サイズを確認する必要はありません。

したがって、ジャンプは発生しませんが、次のことを考慮してください。複数のconnectedリストがあり、それらは垂直に配置されています。今これが起こります:

  1. 上のリストからドラッグを開始します
  2. 上のリストの高さが固定されました
  3. アイテムを一番下のリストに移動します
  4. 一番下のリストは、その高さがautoであるため、うまく調整されます。
  5. 上のリストは同じ固定高さですが1項目短くする必要があります

したがって、ある時点で、その高さをautoに戻す必要があります。いつ? mouseupでは遅すぎます( https://jsfiddle.net/937vv4tx/1/ を参照)が、問題ありません。ジャンプがノーになった直後に正しい値を返すことができますもっと脅威。 start()イベントの使用

更新:ただし、アイテムをクリックするだけで、.mouseup()の高さをautoに設定する必要があります。ドラッグを開始しないでください。.mousedown()が既に発生しているため、固定の高さが設定されます。

$('.sortable').mousedown(function() {
    // set fixed height to prevent scroll jump
    // when dragging from bottom
    $(this).height($(this).height());
}).mouseup(function () {
    // set height back to auto 
    // when user just clicked on item
    $(this).height('auto');
}).sortable({
    connectWith: '.sortable',
    placeholder: 'placeholder',
    start: function() {
        // dragging is happening
        // and scroll jump was prevented,
        // we can set it back to auto
        $(this).height('auto');
    }
});

このコードは私にとって完璧に機能します。

5
Vít Rotbauer

笑、これは4年経ってもまだパッチが適用されていないようです。これが チケット です。

@Carl M. Gregoryの回答に加えて、動的コンテナーを固定の高さに設定する代わりに完全に活用するには、jquery.ui.sortable.jsコアファイルを編集します。

228行目を戻すだけです。208行目の前に_this._createPlaceHolder..._。this.helper.css("position", "absolute");

JqueryチケットポータルのHondaに感謝します。 Sortable.jsバージョン1.10.3を使用しています。

5
Ricky Boyce

だから、複雑!親(ul、#element、whatever_you_call_it)にoverflow: auto;を追加するだけで、機能するはずです。これにより、ドキュメントの高さがわずかに変更された場合でも、サイズ変更時にオーバーフロー自動で要素の高さが保持されます。

3
Webmaster G

素晴らしいソリューションをありがとうございますが、代わりに以下を使用することをお勧めします:

create:function(){
    var list=this;
    resize=function(){
        jQuery(list).css("min-height","0");
        jQuery(list).height(jQuery(list).height());
    };
    jQuery(list).css('min-height', jQuery(list).height());
}
3
Avi Malka

カール・M・グレゴリーは「なぜこれが起こっているのか」を非常に明確に説明しています。

ただし、ウィンドウのサイズを変更すると内部コンテンツが高くなる可能性があるため、高さを固定するだけでは不十分なようです。

私がしたいこと:

  1. 並べ替え可能な「開始」イベントをリッスンし、並べ替え可能なコンテナの高さを修正します
  2. 並べ替え可能な「停止」イベントをリッスンし、高さを自動に戻します(ウィンドウのサイズを変更するときに問題がないことを確認するため)

実際に何が起こるか:ジャンプは開始イベントをキャッチする前に発生するため、これは使用できません

回避策:ソート可能なアイテムのjquerymousedownおよびmouseupイベントをリッスンします。それは非常に簡単です。

$(".sortable_item").mousedown(function(){
    $(".sortable_container").height($(".sortable_container").height());
}).mouseup(function(){
    $(".sortable_container").height('auto');
});

画像の読み込みに関するCarlのポイントを引き続き検討することをお勧めします。彼の答えは一読の価値があります。

2
RaphKomjat

JQuery UI1.9.2で問題が解決したようです。

ライブラリを変更できない場合は、単純なスクロールバー操作を含む回避策があります。アイデアは単純です:

  • スクロールするたびに前のスクロール位置を保持します。
  • 要素のドラッグを開始するときに、スクロールを前の位置に戻します。

どうぞ;

var lastScrollPosition = 0; //variables defined in upper scope
var tempScrollPosition = 0;

window.onscroll = function () { // Up to you requirement you may change it to another elemnet e.g $("#YourPanel").onscroll
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function () {
        tempScrollPosition = lastScrollPosition; // Scrolls don't change from position a to b. They cover some numbers between a and b during the change to create a smooth sliding visual. That's why we pick the previous scroll position with a timer of 250ms.
    }, 250));

    lastScrollPosition = $(document).scrollTop(); // Up to you requirement you may change it to another elemnet e.g $("#YourPanel").onscroll
};

$("#YourSortablePanel").sortable({
    start: function (event, ui) {
        $(document).scrollTop(tempScrollPosition);
    }
});
1
Barry Guvenkaya

これが私が問題を解決する方法です。

   $(".groups").sortable({
    ...
    helper: function(event, ui){
      lastScrollPosition =  $("body").scrollTop();
    },
    start: function(e, ui){
        // avoid scroll jump
        $("body").scrollTop(lastScrollPosition);
    },
   });
0
kastelli

並べ替え可能なdiv VIA Ajaxを自動高さのラッパーにロードしていました。

並べ替え可能なイベントにリンクしようとする代わりに、リストを読み込んで変更するときに高さを自動化し、その後静的な高さに設定しました。

Vitのソリューションも同様ですが、すべてのmousedownおよびmouseupイベントでこれを実行することにより、不要なオーバーヘッドを追加したくありませんでした。代わりに、ロード時にリストが変更されているとき、または新しい要素が追加されたときに実行します(slideDownアニメーションを使用し、完了時に高さを静的に設定します)。

$("#wrapper").load("list.php",function() {
    $("#wrapper").css({ "height":"auto" });
    $("#wrapper").css({ "height": $("#wrapper").height() });
}

他のソリューションは、ページの読み込み中に1回だけ並べ替え可能にしたため、データを再読み込みしたときに機能しませんでした。

私のリスト/ divはドロップダウンで変わるので、別のリストを選択することができ、それに応じてラッパーのサイズが変更されます。

要素を追加したり、何かをリロードしたりする必要がある場合は、これら2行のコードを関数にスローして、関数を呼び出します。

これが誰かを助けることを願っています!

0
user1274820

この問題を解決するためのもう1つの簡単なオプションがあります。

  1. 並べ替えアイコンをマウス入力すると、

    $("body").css("overflow-y","hidden");
    
  2. 並べ替えアイコンをマウスのままにするとき

    $("body").css("overflow-y","scroll");
    
0
Peter Tsai

Chromeでこの問題が発生しました。そして、すべてのソート可能なdivの高さは固定されていました。

問題はcssプロパティにありましたposition: relativeこれらのdivの。 divをドラッグしてDOMから削除すると、相対位置が原因​​で座標が正しく計算されませんでした。

ソート可能な要素には、Inheritまたはabsoluteの配置を使用する必要があります。

0
JuliaCesar