n 個のコンテナ要素による無限スクロールの実装コード

n 個のコンテナ要素による無限スクロールの実装コード

シナリオ

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

無限ドロップダウン読み込みテクノロジーにより、ユーザーは大きなコンテンツ ブロックを表示するためにスクロールし続ける必要があります。このアプローチでは、下にスクロールするたびに新しいコンテンツが継続的に読み込まれます。

スクロールをデータを発見する主な方法として使用すると、ユーザーがページに長く留まり、ユーザーのエンゲージメントが向上します。ソーシャル メディアの普及により、ユーザーによって大量のデータが消費されるようになりました。無限スクロールにより、ユーザーはページのプリロードを待たずに大量の情報を効率的に閲覧できるようになります。

考え方を変えて、ページが 10,000 個の全幅コンポーネントで構成されている場合、5 つのコンポーネントを使用してページ全体を動的にレンダリングするにはどうすればよいでしょうか。

解決

ページング、遅延読み込みなど、長いリストを最適化するためのソリューションは多数あります。 非常に良いインタラクション(菊の絵)があり、ユーザーは待つことができます。この計画も大成功でした。

別のアプローチを見つけるにはどうすればよいでしょうか?

1. シングルページアプリケーションで、ページングソリューションを分析できますか?ページごとに10個の要素があり、各ページングは​​10個の要素を次のようにレンダリングします。

2. 括弧を使用してリスト全体の長さをサポートし、画面が対応する位置までスクロールしたときに対応する 10 個の要素をレンダリングできますか?

ちらつきの問題

このアイデアを実装すると、ちらつきの問題が発生します。スクロール イベントが頻繁に発生するため、遷移するたびにレンダリングする必要がある 10 個の要素を見つけて直接置き換えるため、表示される要素が常に再描画されます。

ここでのアイデアは、画面上の見える位置に 10 個をレンダリングし、次に上方向と下方向に 10 個のレンダリングを導出して、合計 30 個にすることです。レンダリングを制御するときは、常に上部または下部の要素を置き換えて、中央に見える部分を再描画する必要がないようにする必要があります。事前にレンダリングされたデータを再描画するだけです。

原理

5 要素の固定ウィンドウ サイズで n 項目のリストを表示できるコンポーネントを実装します。つまり、いつでも、無限スクロール n 要素上に 5 つの DOM コンテナーのみがあります。

 <ul>
        <li style="transform: translate3d(0px, 0px, 0px);">……</li>
        <li style="transform: translate3d(0px, 60px, 0px);">……</li>
    </ul>
  • 長いリストの内容は、通常、規則的なパターンを持っています。このリストの高さは、<li> の数によって直接計算できます。たとえば、要素が 1000 個あり、各要素の高さが 60 ピクセルの場合、リスト全体の高さは 60000 ピクセルであることがすぐにわかります。
  • コンテナを作成した後、内部の <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] である必要があります。絶対位置に配置されているため、標準フローから外れます。1 回の再描画は他の 4 つに影響を与えないため、パフォーマンスが向上します。

達成方法

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

<ヘッド>
  <メタ文字セット="UTF-8">
  <meta name="viewport" content="width=デバイス幅、初期スケール=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>ドキュメント</title>
  <スタイル>
    体、
    ウル、
    li {
      マージン: 0;
      パディング: 0;
      リストスタイル: なし;
    }

    ul {
      位置: 相対的;
    }

    ul li {
      位置: 絶対;
      上: 0;
      幅: 100%;
      高さ: 31px;
      行の高さ: 32px;
      下境界線: 1px 実線 #ccc;
    }
  </スタイル>
</head>

<本文>
  <ul>
  </ul>
</本文>
<スクリプト>
  // コンテナの合計 var list = [];
  // 表示範囲内の要素コンテナ var showList = [];
  // レンダリングコンテナ var renderList = [];
  // 各コンテナの高さ var lineHeight = 32

  // 1000 要素を初期化します for (var i = 0; i < 1000; i++) {
    list.push({ id: i, text: '第' + (i + 1) + '個要素', top: i * lineHeight, bottom: (i + 1) * lineHeight })
  }
  // コンテナの高さを初期化します $('ul').attr('style', 'height:' + 1000 * lineHeight + 'px')
  // コンテナを初期化する関数を見つける render(top, bottom) {
    表示リスト = []
    // レンダリングされたデータでどのデータが繰り返されるかをマークし、この部分は繰り返しレンダリングされません var sameIndex = []
    // スクロール位置がどの要素にあるか調べる var currentIndex = 0
    (var i = 0; i < list.length; i++) の場合 {
      var アイテム = リスト[i]
      (item.top <= window.scrollY && item.bottom > window.scrollY){
        現在のインデックス = i;
        壊す;
      }
    }
    変数範囲 = 0
    // 現在見つかった要素の上下に表示される要素を、合計数が 35 に達するまで検索します while (range < 100 && showList.length + sameIndex.length < 35) {
      if (currentIndex - 範囲 >= 0) {
        // 条件を満たす要素がレンダリングされたリストにあるかどうかを比較します。ある場合はマークします。ない場合は showList に入れて、その時点でマークされていない要素を置き換えます。if (renderList.includes(list[currentIndex - range].id)) {
          // sameIndex.push(現在のインデックス範囲)
          sameIndex.unshift(renderList.indexOf(リスト[現在のインデックス - 範囲].id))
        } それ以外 {
          showList.unshift(リスト[現在のインデックス - 範囲])
        }
      }

      (currentIndex + range < list.length && range != 0) の場合 {
        if (renderList.includes(list[currentIndex + range].id)) {
          sameIndex.push(renderList.indexOf(リスト[現在のインデックス + 範囲].id))
        } それ以外 {
          showList.push(リスト[現在のインデックス + 範囲])
        }
      }
      範囲++
    }
    // レンダリングする必要がある新しい要素を、レンダリングリスト内のマークされていない要素に置き換えます。if (renderList.length > 0) {
      (var i = 0; i < renderList.length; i++) {
        if (!sameIndex.includes(i) && showList.length) {
          レンダリングリスト[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);')
        }
      }
    } それ以外 {
      // リストを初めて初期化する renderList = showList.map(function (val) { return val.id })
      renderList.map(関数 (キー) {
        $('ul').append($('<li style="transform: translate3d(0px, ' + list[key].top + 'px, 0px);"">#' + list[key].id + list[key].text + '</li>'))
      })
    }
    コンソールログ(レンダリングリスト)
  }
  // 最初のレンダリング render()
  $(window).scroll(関数(e) {
    与える()
  });

</スクリプト>

</html>

やるべきこと

  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 を通じて位置と高さを計算すると、最初の読み込みパフォーマンスが消費されます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

<<:  JavaScriptプロトタイプチェーン図のまとめと実践

>>:  位置固定オフセット問題を解決する方法の詳細な説明

推薦する

Visual Studio Codeを使用してMySqlデータベースに接続し、クエリを実行します。

Visual Studio Code は、Microsoft が開発した強力なテキスト エディター...

Linux で boost.python を使用して C++ 動的ライブラリを呼び出す方法

序文最近、C++ 動的ライブラリをテストするためにロボット フレームワークを使い始めました。ロボット...

マークアップ言語 - フレーズ要素

123WORDPRESS.COM HTML チュートリアル セクションに戻るには、ここをクリックして...

JavaScript 非同期プログラミングにおける Promise の初期の使用法の詳細な説明

1. 概要Promise オブジェクトは、ES6 で提案された非同期プログラミングの仕様です。非同期...

JavaScript継承のさまざまな方法とメリット・デメリットを詳しく解説

目次1. プロトタイプチェーン継承2. コンストラクタの借用(古典的な継承) 3. 組み合わせ継承4...

MySQL 8.0.12 インストール設定方法とパスワード変更

この記事ではMySQL 8.0.12のインストールと設定方法を参考までに記録します。具体的な内容は以...

MySQL 5.7.20 のインストールと設定方法のグラフィック チュートリアル (win10)

この記事では、MySQL 5.7.20のインストールと設定方法を参考までに紹介します。具体的な内容は...

MySQLプロセスを安全かつ適切にシャットダウンする方法

序文この記事では、mysqld プロセスをシャットダウンするプロセスと、MySQL インスタンスを安...

Django がローカル MySQL データベースに接続する手順 (pycharm)

ステップ1:setting.pyでデータベースを変更する # データベースを構成する DATABAS...

HTML でシンプルな ListViews 効果を実装するためのサンプル コード

シンプルなリストビュー効果を実現するHTML結果: CSS スタイル ファイル listviewTe...

Linux ドライバ開発でよく使われる関数 copy_from_user open read write の詳細な説明

目次Linux ドライバーの共通機能 (copy_from_user open read write...

レスポンシブレイアウトの概要(推奨)

レスポンシブレイアウト開発の基礎知識この章は主に以下の部分に分かれています• レスポンシブデザインを...

Vue の 2 択タブバー切り替えの新しいアプローチ

問題の説明プロジェクトに取り組んでいるときに、タブ バーの切り替え効果を作成する必要がある場合があり...

Dockerでmysqlのルートパスワードを変更する方法

最初のステップはmysqlコンテナを作成することです docker exec -it コンテナID ...

Linux コマンドラインターミナルで画面を分割するための 2 つのツール

ターミナル分割画面ツールは2つあります: screen と tmux 1. 画面分割を使用する(上下...