WeChatアプレットは固定ヘッダーとリストテーブルコンポーネントを実装します

WeChatアプレットは固定ヘッダーとリストテーブルコンポーネントを実装します

必要:

WeChatアプレットは固定ヘッダーと固定列のテーブルコンポーネントを実装します(若干の変更を加えることでモバイル端末にも適用可能)

機能ポイント

  • ソートテーブル
  • ヘッダーは固定できる
  • 最初の列は固定されています(指定した列の左側と右側を固定するように構成するように最適化できます)
  • ページめくり(上に引っ張って読み込む)の監視

レンダリング

実装のアイデア

スクロールの連動を実装するために、3 つの ScrollView を使用することを考え始めました。ヘッダーと列が固定されている場合、テーブルの内容がスクロールすると、ヘッダーと列もそれに応じてスクロールする必要があります。デモを作成した後、1 つの ScrollView の位置情報を監視して他の 2 つの ScrollView の位置を設定するのは非常に面倒で、エクスペリエンスが非常に悪いことがわかりました。position:sticky; を使用して、ヘッダーをテーブルの上部に固定し、各行の最初の要素を現在の行の左側に固定します。

発生した問題:

  • テーブルを左にスライドすると、固定列は 1 画面分スライドした後、画面外にスライドします。解決策: テーブルの幅を動的に設定します。原則: スライド アウトする理由は、行全体が画面からスライド アウトし、スティッキーが行全体の左側を基準に配置されるためです。
  • テーブルの高さを 100% に設定すると、useReachBottom プルアップ監視が失敗します。テーブルの高さを高く設定すると、固定ヘッダーが失敗します。解決策: ScrollViewを使用してテーブルを折り返し、onScrollToLowerを使用して読み込みをリッスンします。

具体的なコード(react\taro3.0)

インデックス.tsx

/**
 * スライド可能、固定ヘッダー、固定列のテーブル コンポーネント* @example <Table data={data} dataAttribute={dataAttribute} sortTypeChange={sortTypeChange} handleRow={toDetails}/>
 */

'react' から React、{useState、useMemo、useEffect} をインポートします。
'classnames' から classNames をインポートします

// コンポーネント
'@tarojs/components' から { View, Text, ScrollView } をインポートします。

// ユーティリティ
'@/utils/util' から { noop } をインポートします

// スタイル
'./index.module.less' からスタイルをインポートします

インターフェース DataAttributeItem {
  タイトル: 文字列
  キー: 文字列 | 数値
  ソートキー?: 文字列 | 数値
}

インターフェースProps{
  データ: 配列<任意>
  データ属性: 配列<データ属性項目>
  sortTypeChange?: (sort_item_id: 任意、sort_desc: ブール値) => void
  handleRow?: (データ: 任意) => void
  handleScrollToLower?: (e: 任意) => void
}

デフォルトの関数Table(props: Props)をエクスポートします。
  const { data、dataAttribute、sortTypeChange = noop、handleRow = noop、handleScrollToLower = noop } = props
  const [isSortDesc, setIsSortDesc] = useState<boolean>(true)
  const [sortIndex, setSortIndex] = useState<数値>(1)
  const テーブル幅 = useMemo(() => {
    `${(dataAttribute.length * 148 + 48)}rpx` を返します
  }, [データ属性])

  const テーブルの高さ = useMemo(() => {
    `${((data.length + 1) * 96)}rpx` を返します
  }、 [データ])

  const ハンドルソートアイテム = (属性アイテム、属性インデックス) => {
    属性インデックス === 0 の場合 {
      戻る
    }
    定数 beforeIndex = sortIndex
    定数sortKey = attrItem.sortKey
    dataAttribute.map((item, index)=>{
      if (item.sortKey === sortKey) {
        if (beforeIndex === インデックス) {
          setIsSortDesc(!isSortDesc)
        } それ以外 {
          setSortIndex(インデックス)
          並べ替え順序を設定します(true)
        }
      }
    })
  }

  使用効果(()=>{
    定数 sort_desc = isSortDesc
    const sort_item_id = データ属性[ソートインデックス].sortKey
    ソートタイプ変更(ソート項目ID、ソート順序)
  },[ソートインデックス、isSortDesc])


  戻る (
    <ScrollView className={styles['table']} scrollY scrollX onScrollToLower={handleScrollToLower}>
      <View className={styles['sticky-box']} style={{height: tableHeight}}>
        <View className={styles['grey-box']} style={{width: tableWidth, position: 'sticky'}}/>
        <View className={styles['table__head']} style={{width: tableWidth, position: 'sticky'}}>
          {dataAttribute.map((attrItem, attrIndex) => (
            <View className={styles['table__head__td']} key={attrIndex} onClick={()=>handleSortItem(attrItem, attrIndex)}>
              <テキスト
                クラス名={クラス名({
                  [スタイル['table__head__td__text']]: true,
                  [styles['table__head__td__text-active']]: sortIndex === attrIndex、
                })}
                キー={属性インデックス}
              >{attrItem.title}</テキスト>
              {attrIndex !== 0 && <ビュー
                クラス名={クラス名({
                  [styles['table__head__td__sorter-indicate']]: true,
                  [styles['table__head__td__sorter-indicate--asc-active']]: sortIndex === attrIndex && !isSortDesc,
                  [styles['table__head__td__sorter-indicate--desc-active']]: sortIndex === attrIndex && isSortDesc
                })}
              }}}
            </表示>
          ))}
        </表示>
        {data.map((データ項目、データインデックス) => (
          <View className={styles['table__row']} key={dataIndex} style={{width: tableWidth}} onClick={() => handleRow(dataItem)}>
            {dataAttribute.map((attrItem, attrIndex) => {
              戻る (
                <Text className={styles['table__row__td']} key={attrIndex}>{dataItem[attrItem.key] || '-'}</Text>
              )
            })}
          </表示>
        ))}
      </表示>
    </スクロールビュー>
  )
}

インデックスモジュール

@import '~@/assets/style/mixins/ellipsis.less';
ページ{
  フォントサイズ: 26rpx;
  行の高さ: 60rpx;
  色: #222;
  高さ: 100%;
  幅: 100%;
}
.grey-box{
  高さ: 10rpx;
  上: 0;
  背景: #f8f8f8;
  zインデックス: 100;
}
。テーブル{
  位置: 相対的;
  オーバーフロー: スクロール;
  幅: 100%;
  高さ: 100%;
  オーバーフロー: スクロール;
  &__頭{
    位置: 相対的;
    高さ: 96rpx;
    空白: ラップなし;
    // 位置: スティッキー;
    上: 10rpx;
    zインデックス: 100;
    高さ: 88rpx;
    フォントサイズ: 24rpx;
    行の高さ: 88rpx;
    色: #aaabbd;
    背景色: #f8f8f8;
    下部境界線: 2rpx 実線 #ecf1f8;
    背景色: #fff;
    空白: ラップなし;
    ディスプレイ: フレックス;
    &__td{
      .ellipsis();
      幅: 148rpx;
      // パディング右: 40rpx;
      ディスプレイ: フレックス;
      コンテンツの配置: flex-start;
      アイテムの位置を中央揃えにします。
      背景色: #fff;
      位置: 相対的;
      ボックスのサイズ: 境界線ボックス;
      &:n番目の子(1) {
        左パディング: 24rpx;
        幅: 154rpx;
        右マージン: 40rpx;
        位置: 固定;
        zインデックス: 10;
        左: 0;
      }
      &__文章{
        表示: インライン;
        &-アクティブ{
          色: #6d70ff;
        }
      }
      &__sorter-indicate{
        幅: 24rpx;
        高さ: 24rpx;
        表示: インラインブロック;
        背景繰り返し: 繰り返しなし;
        背景サイズ: 100% 100%;
        背景画像: url('https://icon1.png');
        &--asc-アクティブ {
          背景画像: url('https://icon2.png');
        }
        &--desc-active {
          背景画像: url('https://icon3.png');
        }
      }
    }
  }
  &__行{
    位置: 相対的;
    高さ: 96rpx;
    空白: ラップなし;
    ディスプレイ: フレックス;
    コンテンツの配置: flex-start;
    アイテムの位置を中央揃えにします。
    下部境界線: 2rpx 実線 #ecf1f8;
    &__td{
      // .ellipsis();
      オーバーフロー: スクロール;
      空白: ラップなし;
      幅: 148rpx;
      // パディング右: 40rpx;
      表示: インラインブロック;
      背景色: #fff;
      位置: 相対的;
      ボックスのサイズ: 境界線ボックス;
      フォントサイズ: 26rpx;
      行の高さ: 96rpx;
      &:n番目の子(1) {
        右マージン: 40rpx;
        左パディング: 24rpx;
        幅: 154rpx;
        位置: 固定;
        zインデックス: 10;
        左: 0;
      }
    }
  }
}

特定のコード(ミニプログラムネイティブ)

<ScrollView class="table" scroll-x scroll-y bindscrolltolower="handleScrollToLower">
  <View class="sticky-box" style="height:{{tableHeight}}rpx;">
    <View class="table__head" style="width:{{tableWidth}}rpx;">
      <View class="table__head__td" wx:for="{{dataAttribute}}" wx:key="attrIndex" wx:for-index="attrIndex" wx:for-item="attrItem">
        <テキスト
          クラス="table__head__td__text"
        >{{attrItem.title}}</テキスト>
      </表示>
    </表示>
    <View class="table__row" wx:for="{{data}}" wx:key="dataIndex" wx:for-index="dataIndex" wx:for-item="dataItem" style="width:{{tableWidth}}rpx;">
      <Text class="table__row__td" wx:for="{{dataAttribute}}" wx:key="dataIndex" wx:for-index="attrIndex" wx:for-item="attrItem">{{dataItem[attrItem.key] || '-'}}</Text>
    </表示>
  </表示>
</スクロールビュー>
const アプリ = getApp()
ページ({
  データ: {
    データ: [
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
      {
        123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        女性: 789
      },
    ]、
    データ属性: [
      {
        タイトル: 「最初の列」、
        キー: 'a'
      },
      {
        タイトル: '列2'、
        キー: 'b'
      },
      {
        タイトル: '列3'、
        キー: 'c'
      },
      {
        タイトル: 'コラム4'、
        キー: 'd'
      },
      {
        タイトル: 'コラム5'、
        キー: 'e'
      },
      {
        タイトル: 「コラム6」
        キー: 'f'
      }
    ]、
    テーブルの高さ: (20 + 1) * 96,
    テーブル幅: 200 * 6 + 60
  }
})
ページ{
  フォントサイズ: 26rpx;
  行の高さ: 60rpx;
  色: #222;
  高さ: 100%;
  幅: 100%;
}
。テーブル{
  表示: ブロック;
  位置: 相対的;
  オーバーフロー: スクロール;
  幅: 100%;
  高さ: 100%;
}
.sticky-box{
}
.table__head{
  高さ: 96rpx;
  空白: ラップなし;
  位置: 固定;
  上: 0rpx;
  zインデックス: 100;
  高さ: 88rpx;
  フォントサイズ: 24rpx;
  行の高さ: 88rpx;
  色: #aaabbd;
  背景色: #f8f8f8;
  下部境界線: 2rpx 実線 #ecf1f8;
  背景色: #fff;
  空白: ラップなし;
  ディスプレイ: フレックス;
}
.table__head__td{
  幅: 200rpx;
  ディスプレイ: フレックス;
  コンテンツの配置: flex-start;
  アイテムの位置を中央揃えにします。
  背景色: #fff;
  ボックスのサイズ: 境界線ボックス;
  位置: 相対的;
  オーバーフロー: 非表示;
  空白: ラップなし;
  -o-テキストオーバーフロー:省略記号;
  テキストオーバーフロー: 省略記号;
}
.table__head__td:n番目の子(1) {
  左パディング: 24rpx;
  幅: 260rpx;
  右マージン: 40rpx;
  位置: 固定;
  zインデックス: 101;
  左: 0rpx;
}
.table__head__td__text{
  表示: インライン;
}
.table__row{
  位置: 相対的;
  高さ: 96rpx;
  空白: ラップなし;
  ディスプレイ: フレックス;
  コンテンツの配置: flex-start;
  アイテムの位置を中央揃えにします。
  下部境界線: 2rpx 実線 #ecf1f8;
}
.table__row__td{
  オーバーフロー: スクロール;
  空白: ラップなし;
  幅: 200rpx;
  表示: インラインブロック;
  背景色: #fff;
  ボックスのサイズ: 境界線ボックス;
  フォントサイズ: 26rpx;
  行の高さ: 96rpx;
  位置: 相対的;
  オーバーフロー: 非表示;
  空白: ラップなし;
  -o-テキストオーバーフロー:省略記号;
  テキストオーバーフロー: 省略記号;
}
.table__row__td:n番目の子(1) {
  右マージン: 40rpx;
  左パディング: 24rpx;
  幅: 260rpx;
  位置: 固定;
  zインデックス: 10;
  左: 0;
}

要約する

WeChatミニプログラムで固定ヘッダーとテーブルコンポーネントを実装する方法に関するこの記事はこれで終わりです。WeChatミニプログラムの固定ヘッダーに関する関連コンテンツの詳細については、123WORDPRESS.COMで以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も123WORDPRESS.COMを応援してください。

<<:  MySQLにおけるACIDトランザクションの実装原理の詳細な説明

>>:  SSMプロジェクトは、ホットデプロイメント構成を実装するためにTomcatとMavenを使用してWARパッケージとしてデプロイされることが多い。

推薦する

ワンクリックで雨や雪のエフェクトを実現する ThingJS パーティクルエフェクト

目次1. パーティクルエフェクト2. シーンを読み込む3. さまざまな粒子効果の実現エンディング: ...

MySQL msiバージョンのダウンロードとインストールの初心者向けの詳細なグラフィックチュートリアル

目次1. MySQL msiバージョンをダウンロードする2. インストール3. 環境変数を設定する1...

docker pullがリセットされる問題を解決する

この記事では、docker pull がリセットされる問題を解決する方法を紹介し、皆さんと共有します...

httpsウェブサイトにリファラーhttpsとhttpジャンプリファラーを送信させる方法

この記事では、HTTP プロトコルのリファラーのメタデータ パラメータの提案について説明します。この...

Linux ファイアウォール設定の詳細な手順 (yum ウェアハウス設定に基づく)

序文この実験では、デバッグ用に2つの仮想マシン(CentOs6とRed Hat 6)を準備します。 ...

JVM 上の高性能データ形式ライブラリ パッケージである Apache Arrow の紹介とアーキテクチャ (Gkatziouras)

Apache Arrow は、BigQuery を含むさまざまなビッグデータ ツールで使用される一...

Linux SSHポートを転送する3つの方法

ssh は私が最も頻繁に使用する 2 つのコマンドライン ツールのうちの 1 つです (もう 1 つ...

VMware 仮想マシンのインストール win7 オペレーティング システム チュートリアル ダイアグラム

VMwareaのインストールプロセスは説明しませんが、主にwin7イメージをロードする方法を説明しま...

独自の YUM リポジトリを作成する手順

簡単に言うと、ウェアハウスとして使用される仮想マシンの IP は 192.168.149.129 で...

MySQLデータベースを定期的に自動バックアップする方法

データは貴重なものであることは誰もが知っています。データをバックアップしなければ、データをそのまま放...

JavaScriptでポインターの位置を取得する方法を教えます

JavaScript でポインターの位置を取得する方法は、イベント オブジェクトの pageX と ...

nginx プロキシでの複数の 302 応答の解決策 (nginx Follow 302)

proxy_intercept_errors と recursive_error_pages を使...

NavicatがMySQLに接続すると、10060、1045エラーとmy.iniの場所が報告されます。

Navicat は、データベースに接続するときにエラー 10060 および 1045 を報告します...

モバイルデバイス上の 1px 境界線を解決する最善の方法 (推奨)

モバイル デバイス向けに開発する場合、Retina 画面上で要素の境界線が太くなるという問題に遭遇す...