1. ホーム
  2. Web制作
  3. HTML/Xhtml

n個のコンテナ要素で無限スクロールを実現するコード

2022-01-08 13:21:43

シーン

最大 10,000 要素のリストを正しくレンダリングする方法。

無限ドロップダウン読み込みのテクニックは、ユーザーが大量のコンテンツの塊の中をスクロールし続けることになります。この手法は、スクロールダウンするたびに新しいコンテンツをロードし続けるというものです。

スクロールをデータ発見の主要な方法として使用すると、ユーザーをより長くページにとどめ、ユーザーエンゲージメントを高めることができるかもしれません。ソーシャルメディアの普及により、ユーザーは多くのデータを消費しています。ワイヤレス・スクロールは、ユーザーがページのプリロードを待つことなく、大量の情報を効率的にナビゲートする方法を提供します。

逆に考えると、1万個のパススルー部品が上に乗っているページがあったとして、5個の部品でページ全体をダイナミックにレンダリングするにはどうしたらいいか?

解決案

長いリストを最適化するために、ページングやレイジーローディングなど、多くのオプションがあります。ユーザーを少し待たせるような、とても良いインタラクション(デイジーチャート)もあります。そのようなソリューションも非常に成功しています。

どうすれば他の方法が見つかるか?

1. 1ページあたり10要素で、ページングによって一度に10要素をレンダリングするシングルページアプリケーションにおけるページングスキームの分析を行うことはできますか?

2. ブラケットを使ってリストの全長を保持し、画面が対応する位置までスクロールしたときに、対応する10個の要素をレンダリングできないか

ちらつきの問題

スクロールイベントが頻繁に発生するため、表示される要素が常に再描画されることになり、そのたびにレンダリングが必要な10個の要素を探し、それらを置き換えるだけになってしまうのです。

ここでは、画面位置に10要素、そして上下に10要素、合計30要素をレンダリングし、レンダリングの制御時に必ず上か下の要素を置き換えることで、見えている真ん中の部分を再描画してレンダリングしないようにする、というものです。レンダリング前のデータだけが再描画されるのです。

プリンシプル

固定されたウィンドウサイズで5つの要素を持つn個のアイテムのリストを表示するコンポーネントを実装する。すなわち、任意の時間に無限にスクロールするn個の要素には5つのDOMコンテナしか存在しないようにする。

pic.setController(getController(picStr));


 private DraweeController getController(String picStr) {
        ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(picStr))
                .setResizeOptions(new ResizeOptions(100,100))
                .build();//limit your display size
        DraweeController controller = Fresco.newDraweeControllerBuilder()
                .setImageRequest(request)
                .build();
        return controller;
    }



  • このリストの高さは、<li>要素の数から直接計算することができます。例えば、1000個の要素、それぞれの高さは60pxなので、実際のリストの高さは60000pxとすぐに計算することができます。
  • コンテナができたら、内部の <li> を <ul> に対して絶対的に相対的に配置し、js を使って各 <li> に対応する 'transform: translate3d(0px, 0px, 0px);' 属性を直接算出します。
  • 常にレンダリングされる現在の位置の<li>と比較するレンダリングデータの最後のセットを見つけるためにスクロール時間を聞くことによって、スキップして、異なる要素のレンダリングデータの最後のセットと見つけ、次に対応する置換を行うために同じ<li>がある

例えば、以下のような場合です。100要素は、最初のページには5を示し、初期化[0,1,2,3,4]これらの5 <li> 私は少し下にスクロールすると、レンダリングする必要があり、 [1,2,3,4,5] これらの <li> がある。レンダリングする必要がある、この時間は、直接全体の置換を行うことはありません、唯一の差の項目を置き換える必要があります、構造は、[5,1,2,3,4]にする必要があります、それは絶対に配置されているので、標準の流れから出て、単一の再描画が他の4つに影響しません、したがってパフォーマンスを改善します。

実装方法

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
  <title>Document</title>
  <style>
    body,
    ul,
    li {
      margin: 0;
      padding: 0;
      list-style: none;
    }

    ul {
      position: relative;
    }

    ul li {
      position: absolute;
      top: 0;
      width: 100%;
      height: 31px;
      line-height: 32px;
      border-bottom: 1px solid #ccc;
    }
  </style>
</head>

<body>
  <ul>
  </ul>
</body>
<script>
  // total container
  var list = [];
  // The viewable scope element container
  var showList = [];
  // render container
  var renderList = [];
  // height of each container
  var lineHeight = 32

  // Initialize 1000 elements
  for (var i = 0; i < 1000; i++) {
    list.push({ id: i, text: 'first' + (i + 1) + 'element', top: i * lineHeight, bottom: (i + 1) * lineHeight })
  }
  // Initialize the container height
  $('ul').attr('style', 'height:' + 1000 * lineHeight + 'px')
  // Find the initialized container
  function render(top, bottom) {
    showList = []
    // mark which data is duplicated by the one already rendered, this part will not be rendered repeatedly
    var sameIndex = []
    // Find out which element the scroll position is on
    var currentIndex = 0
    for (var i = 0; i < list.length; i++) {
      var item = list[i]
      if (item.top <= window.scrollY && item.bottom > window.scrollY) {
        currentIndex = i;
        break;
      }
    }
    var range = 0
    // Search up and down for the elements that need to be shown in the currently found elements, until the total number of elements reaches 35
    while (range < 100 && showList.length + sameIndex.length < 35) {
      if (currentIndex - range >= 0) {
        // Compare the elements that meet the condition to see if they are in the rendered list, mark them if they are, and put them in the showList when they are not marked
        if (renderList.includes(list[currentIndex - range].id)) {
          // sameIndex.push(currentIndex-range)
          sameIndex.unshift(renderList.indexOf(list[currentIndex - range].id))
        } else {
          showList.unshift(list[currentIndex - range])
        }
      }

      if (currentIndex + range < list.length && range ! = 0) {
        if (renderList.includes(list[currentIndex + range].id)) {
          sameIndex.push(renderList.indexOf(list[currentIndex + range].id))
        } else {
          showList.push(list[currentIndex + range])
        }
      }
      range++
    }
    // Replace the new rendered elements that are compared with the unmarked render list elements
    if (renderList.length > 0) {
      for (var i = 0; i < renderList.length; i++) {
        if (!sameIndex.includes(i) && showList.length) {
          renderList[i] = showList.shift().id
          $('ul li').eq(i).html(list[renderList[i]].id + list[renderList[i]].text).attr('style', 'transform: translate3d(0px, ' + list[renderList[i] ].top + 'px, 0px);')
        }
      }
    } else {
      // Initialize the list for the first time
      renderList = showList.map(function (val) { return val.id })
      renderList.map(function (key) {
        $('ul').append($('<li style="transform: translate3d(0px, ' + list[key].top + 'px, 0px);"">#' + list[key].id + list[key]. text + '</li>'))
      })
    }
    console.log(renderList)
  }
  // First rendering
  render()
  $(window).scroll(function (e) {
    render()
  });

</script>

</html>

TODO

  1. コンテナ要素を置き換える方法を比較すると、常に、より効率的に実行されるように最適化され、その結果、高速スクロールで発生するホワイトスクリーンを最適化できるように感じられます
  2. こちらも思考問題 [0,1 ......] です。 10000]、そこから5つの要素を取り出すたびに、新たに選択された古いものと比較し、2つの配列の交点を保持し、古い配列の非交差点を新しい配列内の新しい要素で置き換えます。例えば、1回目が[0,1,2,3,4]、2回目が[ 2,3,4,5,6] ならば比較により[ 5,6,2,3,4] 、3回目が[ 4,5,6,7,8] であるならば[ 5,6,7,8,4] が生成されます。この結果の配列を最小のコード数で取得する。

概要

  1. データでレイアウトと初期化を完了
  2. コンテナの位置を感じて標準フローから抜け出す
  3. データを比較し、できるだけ少ないコンテナ要素を一度に再描画することで、不一致のコンテナ要素を特定します。

次ページ ----- ロングリストを実装したコンポーネント

キーポイント

  1. 通常のリストと異なり、コンポーネントの高さは制御できないため、モバイルデバイスによって変化します
  2. コンポーネントの高さが同じでも、コンテナの数が異なるため、レンダリングエリア内のコンポーネント数が異なる
  3. データから直接計算するのが容易でない高さの場合、一度全体をレンダリングしてからdomで位置と高さを計算するのは、最初のロードパフォーマンスに非常にコストがかかる。

今回の記事は以上です。皆さんの学習のお役に立てれば幸いです。そして、スクリプトハウスを応援していただければ幸いです。