3

ブラウザのスクロール イベントを使用して、ユーザーがスクロールした量に基づいて html のブロックを配置しようとしています。コードは機能しますが、基本的にブラウザをフリーズさせる大きなパフォーマンスの問題を引き起こしています。

これを解決するために私ができる理由と解決策についての洞察をいただければ幸いです。

<script type="text/javascript">

$('#content').scroll(function () {
    var scroll = $('#content').scrollTop();
    var $controls = $(".controls").clone();
    if (scroll > 200) {
        $(".controls").remove();
        $('#header').append($controls);
    }
    else {
        $(".controls").remove();
        $('.banner').append($controls);
    }
});

</script>
4

4 に答える 4

14

まず、DOM 内の要素を検出するのはコストがかかるため、jQuery オブジェクトをキャッシュします。

第二に、.append()要素を移動するため.clone()remove()不要なはずです。

これは与える :

var $$ = {//cache of jQuery objects
    content: $('#content'),
    controls: $(".controls"),
    header: $("#header"),
    banner: $('.banner')
};
$('#content').scroll(function() {
    $controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
});

これで、ハンドラーが呼び出される頻度を減らすことができます。これは次のように達成できます。

var $$ = {//cache of jQuery objects
    content: $('#content'),
    controls: $(".controls"),
    header: $("#header"),
    banner: $('.banner')
};

var scrollHandling = {
    allow: true,
    reallow: function() {
        scrollHandling.allow = true;
    },
    delay: 50 //(milliseconds) adjust to the highest acceptable value
};

$('#content').scroll(function() {
    if(scrollHandling.allow) {
        $controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
        scrollHandling.allow = false;
        setTimeout(scrollHandling.reallow, scrollHandling.delay);
    }
});
于 2013-02-02T03:31:55.477 に答える
3

このscroll関数は、スクロールバーが移動するたびに呼び出されます。これは潜在的に何度も発生する可能性があるため、実行しているコードの量と、実行している DOM の操作量に注意する必要があります。

この場合、スクロールが発生している間、多くの同じアクション ( cloneappend、 ) を繰り返しますが、その 200 の値removeを前後に交差するときに 2 つの状態の間を反転したいだけのようです。scroll次のような方法で、パフォーマンスの問題のほとんどを解決できる可能性があります。

<script type="text/javascript">

var thresholdCrossed = false;

$('#content').scroll(function () {
    var scroll = $('#content').scrollTop();
    var threshold = 200;
    if (scroll > threshold && !thresholdCrossed) {
        var controls = $(".controls").clone();
        $(".controls").remove();
        $('#header').append(controls);
    } else if (scroll <= threshold && thresholdCrossed) {
        var controls = $(".controls").clone();
        $(".controls").remove();
        $('.banner').append(controls);
    }
    thresholdCrossed = scroll > threshold;
});

</script>

無駄なリソースを減らすために、他の回答のいくつかで説明されている追加の作業を行うことができますが、これにより、スクロール時にDOMを常に変更するという主なパフォーマンスの問題をうまく解決する方法の一般的なアイデアが得られます。DOM操作を必要最小限に制限できるように、@Kolinkが提供する回答とこれを組み合わせることをお勧めします。

于 2013-02-02T03:23:50.120 に答える
2

.controls必要がない場合でも、スクロールの目盛りごとにすべての要素を複製しています。

コントロールを複製してreadyに設定することをお勧めしdisplay:noneます。次に、スクロール位置に基づいて表示を切り替えるだけです。


質問を読み直すと、コントロール要素を から ? に移動しているように見えheaderますbanner。その場合、クローンさえ必要ありません。id="controls"ただし、controls 要素に追加することを強くお勧めしid="banner"ます。クラスが 1 つしかない場合は、一般的にクラスの代わりに ID を使用します。

document.getElementById('content').onscroll = function() {
    document.getElementById(this.scrollTop > 200 ? "banner" : "header")
       .appendChild(document.getElementById('controls'));
};
于 2013-02-02T03:09:35.027 に答える
0

スクロール バーが移動するたびに、jQuery は DOM に入り、参照する変数を取得する必要があります。変数のキャッシュを開始して、jQuery が 2 倍の作業を行う必要がないようにします。

          var content = $('#content');

          content.scroll(function(){


          });
于 2013-02-02T03:11:51.110 に答える