溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

微信小程序中怎么實(shí)現(xiàn)一個(gè)固定表頭、列表格組件

發(fā)布時(shí)間:2021-07-02 13:50:56 來源:億速云 閱讀:1130 作者:Leah 欄目:開發(fā)技術(shù)

微信小程序中怎么實(shí)現(xiàn)一個(gè)固定表頭、列表格組件,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

實(shí)現(xiàn)思路

開始想用三個(gè)ScrollView去實(shí)現(xiàn)滾動(dòng)聯(lián)動(dòng),固定表頭、列的話,表格內(nèi)容滾動(dòng)表頭、列也應(yīng)該對應(yīng)滾動(dòng),寫了demo后發(fā)現(xiàn)監(jiān)聽一個(gè)ScrollView的位置信息去設(shè)置另外兩個(gè)ScrollView的位置真機(jī)會(huì)很卡,體驗(yàn)極差
使用position:sticky; 讓表頭相對表格頂部sticky,每行的第一個(gè)元素相對當(dāng)前行左側(cè)sticky。

遇到的問題:

  • 表格左滑的時(shí)候,滑動(dòng)一個(gè)屏幕后固定列跟著滑出屏幕了。解決方法:動(dòng)態(tài)設(shè)置表格的寬度,原理:滑出去的原因是整行滑出屏幕了,而sticky是相對整行左側(cè)定位的。

  • 表格高度設(shè)置為100%后useReachBottom上拉監(jiān)聽失效 將表格高度設(shè)高的話固定表頭就失效了。解決方法:表格用ScrollView套一層使用onScrollToLower監(jiān)聽加載

具體代碼(react\taro3.0)

index.tsx

/**
 * 可滑動(dòng)、固定表頭、固定列表格組件
 * @example <Table data={data} dataAttribute={dataAttribute} sortTypeChange={sortTypeChange} handleRow={toDetails}/>
 */

import React, { useState, useMemo, useEffect } from 'react'
import classNames from 'classnames'

// components
import { View, Text, ScrollView } from '@tarojs/components'

// utils
import { noop } from '@/utils/util'

// styles
import styles from './index.module.less'

interface DataAttributeItem {
  title: string
  key: string | number
  sortKey?: string | number
}

interface Props {
  data: Array<any>
  dataAttribute: Array<DataAttributeItem>
  sortTypeChange?: (sort_item_id: any, sort_desc: boolean) => void
  handleRow?: (data: any) => void
  handleScrollToLower?: (e: any) => void
}

export default function Table(props: Props) {
  const { data, dataAttribute, sortTypeChange = noop, handleRow = noop, handleScrollToLower = noop } = props
  const [isSortDesc, setIsSortDesc] = useState<boolean>(true)
  const [sortIndex, setSortIndex] = useState<number>(1)
  const tableWidth = useMemo(() => {
    return `${(dataAttribute.length * 148 + 48)}rpx`
  }, [dataAttribute])

  const tableHeight =  useMemo(() => {
    return `${((data.length + 1) * 96)}rpx`
  }, [data])

  const handleSortItem = (attrItem, attrIndex) => {
    if (attrIndex === 0) {
      return
    }
    const beforeIndex = sortIndex
    const sortKey = attrItem.sortKey
    dataAttribute.map((item, index)=>{
      if (item.sortKey === sortKey) {
        if (beforeIndex === index) {
          setIsSortDesc(!isSortDesc)
        } else {
          setSortIndex(index)
          setIsSortDesc(true)
        }
      }
    })
  }

  useEffect(()=>{
    const sort_desc = isSortDesc
    const sort_item_id = dataAttribute[sortIndex].sortKey
    sortTypeChange(sort_item_id,sort_desc)
  },[sortIndex, isSortDesc])


  return (
    <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)}>
              <Text
                className={classNames({
                  [styles['table__head__td__text']]: true,
                  [styles['table__head__td__text-active']]: sortIndex === attrIndex,
                })}
                key={attrIndex}
              >{attrItem.title}</Text>
              {attrIndex !== 0 && <View
                className={classNames({
                  [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
                })}
              />}
            </View>
          ))}
        </View>
        {data.map((dataItem, dataIndex) => (
          <View className={styles['table__row']} key={dataIndex} style={{width: tableWidth}} onClick={() => handleRow(dataItem)}>
            {dataAttribute.map((attrItem, attrIndex) => {
              return (
                <Text className={styles['table__row__td']} key={attrIndex}>{dataItem[attrItem.key] || '-'}</Text>
              )
            })}
          </View>
        ))}
      </View>
    </ScrollView>
  )
}

index.module.less

@import '~@/assets/style/mixins/ellipsis.less';
page{
  font-size: 26rpx;
  line-height: 60rpx;
  color: #222;
  height: 100%;
  width: 100%;
}
.grey-box{
  height: 10rpx;
  top: 0;
  background: #f8f8f8;
  z-index: 100;
}
.table{
  position: relative;
  overflow: scroll;
  width: 100%;
  height: 100%;
  overflow: scroll;
  &__head{
    position: relative;
    height: 96rpx;
    white-space: nowrap;
    // position: sticky;
    top: 10rpx;
    z-index: 100;
    height: 88rpx;
    font-size: 24rpx;
    line-height: 88rpx;
    color: #aaabbd;
    background-color: #f8f8f8;
    border-bottom: 2rpx solid #ecf1f8;
    background-color: #fff;
    white-space: nowrap;
    display: flex;
    &__td{
      .ellipsis();
      width: 148rpx;
      // padding-right: 40rpx;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      background-color: #fff;
      position: relative;
      box-sizing: border-box;
      &:nth-child(1) {
        padding-left: 24rpx;
        width: 154rpx;
        margin-right: 40rpx;
        position: sticky;
        z-index: 10;
        left: 0;
      }
      &__text{
        display: inline;
        &-active{
          color: #6d70ff;
        }
      }
      &__sorter-indicate{
        width: 24rpx;
        height: 24rpx;
        display: inline-block;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        background-image: url('https://icon1.png');
        &--asc-active {
          background-image: url('https://icon2.png');
        }
        &--desc-active {
          background-image: url('https://icon3.png');
        }
      }
    }
  }
  &__row{
    position: relative;
    height: 96rpx;
    white-space: nowrap;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    border-bottom: 2rpx solid #ecf1f8;
    &__td{
      // .ellipsis();
      overflow: scroll;
      white-space: nowrap;
      width: 148rpx;
      // padding-right: 40rpx;
      display: inline-block;
      background-color: #fff;
      position: relative;
      box-sizing: border-box;
      font-size: 26rpx;
      line-height: 96rpx;
      &:nth-child(1) {
        margin-right: 40rpx;
        padding-left: 24rpx;
        width: 154rpx;
        position: sticky;
        z-index: 10;
        left: 0;
      }
    }
  }
}

具體代碼(小程序原生)

<ScrollView class="table" scroll-x scroll-y bindscrolltolower="handleScrollToLower">
  <View class="sticky-box" >
    <View class="table__head" >
      <View class="table__head__td" wx:for="{{dataAttribute}}" wx:key="attrIndex" wx:for-index="attrIndex" wx:for-item="attrItem">
        <Text
          class="table__head__td__text"
        >{{attrItem.title}}</Text>
      </View>
    </View>
    <View class="table__row" wx:for="{{data}}" wx:key="dataIndex" wx:for-index="dataIndex" wx:for-item="dataItem" >
      <Text class="table__row__td" wx:for="{{dataAttribute}}" wx:key="dataIndex" wx:for-index="attrIndex" wx:for-item="attrItem">{{dataItem[attrItem.key] || '-'}}</Text>
    </View>
  </View>
</ScrollView>
const app = getApp()
Page({
  data: {
    data: [
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
      {
        a: 123,
        b: 456,
        c: 489,
        d: 789,
        e: 458,
        f: 789
      },
    ],
    dataAttribute: [
      {
        title: '第一列',
        key: 'a'
      },
      {
        title: '第2列',
        key: 'b'
      },
      {
        title: '第3列',
        key: 'c'
      },
      {
        title: '第4列',
        key: 'd'
      },
      {
        title: '第5列',
        key: 'e'
      },
      {
        title: '第6列',
        key: 'f'
      }
    ],
    tableHeight: (20 + 1) * 96,
    tableWidth: 200 * 6 + 60
  }
})
page{
  font-size: 26rpx;
  line-height: 60rpx;
  color: #222;
  height: 100%;
  width: 100%;
}
.table{
  display: block;
  position: relative;
  overflow: scroll;
  width: 100%;
  height: 100%;
}
.sticky-box{
}
.table__head{
  height: 96rpx;
  white-space: nowrap;
  position: sticky;
  top: 0rpx;
  z-index: 100;
  height: 88rpx;
  font-size: 24rpx;
  line-height: 88rpx;
  color: #aaabbd;
  background-color: #f8f8f8;
  border-bottom: 2rpx solid #ecf1f8;
  background-color: #fff;
  white-space: nowrap;
  display: flex;
}
.table__head__td{
  width: 200rpx;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  background-color: #fff;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
  -o-text-overflow: ellipsis;
  text-overflow: ellipsis;
}
.table__head__td:nth-child(1) {
  padding-left: 24rpx;
  width: 260rpx;
  margin-right: 40rpx;
  position: sticky;
  z-index: 101;
  left: 0rpx;
}
.table__head__td__text{
  display: inline;
}
.table__row{
  position: relative;
  height: 96rpx;
  white-space: nowrap;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  border-bottom: 2rpx solid #ecf1f8;
}
.table__row__td{
  overflow: scroll;
  white-space: nowrap;
  width: 200rpx;
  display: inline-block;
  background-color: #fff;
  box-sizing: border-box;
  font-size: 26rpx;
  line-height: 96rpx;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
  -o-text-overflow: ellipsis;
  text-overflow: ellipsis;
}
.table__row__td:nth-child(1) {
  margin-right: 40rpx;
  padding-left: 24rpx;
  width: 260rpx;
  position: sticky;
  z-index: 10;
  left: 0;
}

關(guān)于微信小程序中怎么實(shí)現(xiàn)一個(gè)固定表頭、列表格組件問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI