您好,登錄后才能下訂單哦!
微信小程序中怎么實(shí)現(xiàn)一個(gè)固定表頭、列表格組件,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
開始想用三個(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)聽加載
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í)。
免責(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)容。