need:WeChat applet implements fixed header and fixed column table components (applicable to mobile terminals with some minor modifications) Function Points
RenderingImplementation ideasI started to think of using three ScrollViews to implement scroll linkage. If the header and columns are fixed, the header and columns should scroll accordingly when the table content scrolls. After writing a demo, I found that it would be very stuck to monitor the position information of one ScrollView to set the position of the other two ScrollViews, and the experience was extremely bad. Use position: sticky; to make the header stick to the top of the table, and the first element of each row stick to the left side of the current row. Problems encountered:
Specific code (react\taro3.0)index.tsx /** * Slidable, fixed header, fixed column table components* @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; } } } } Specific code (Mini Program native)<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"> <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" 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> </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: 'First column', key: 'a' }, { title: 'Column 2', key: 'b' }, { title: 'Column 3', key: 'c' }, { title: 'Column 4', key: 'd' }, { title: 'Column 5', key: 'e' }, { title: 'Column 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; } SummarizeThis is the end of this article about how to implement fixed headers and table components in WeChat Mini Programs. For more relevant content about fixed headers in WeChat Mini Programs, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future! |
<<: Detailed explanation of the implementation principle of ACID transaction in Mysql
You can easily input Chinese and get Chinese outp...
Table of contents Preface preparation Go! text St...
Table of contents Problem Description Rendering T...
This article takes the deployment of Spring boot ...
Run the command: glxinfo | grep rendering If the ...
The file server is one of the most commonly used ...
A recent business involves such a requirement tha...
The other day I was using rsync to transfer a lar...
Today I made a Spring Festival gold coin red enve...
After installing VMware and creating a new virtua...
To connect Node-red to the database (mysql), you ...
Vue calls the PC camera to take pictures in real ...
Our network management center serves as the manag...
Table of contents Overview Single file components...
Table of contents [See an example]: [The original...