再也不怕Table表格滚动了

338 阅读3分钟

一、 前言

这篇文章就主要来讲一下大屏滚动的几种方案,当然,如果大家有其他方案,欢迎在评论区点拨一下小弟,废话不多说,直接进入正题

二、方案集合

2.1、利用色差

利用色差效果给用户一个“滚屏”的体验,使用这种方案的前提是斑马色要有足够的色差感,这里使用antd 的table为例,效果如下:

表格滚动1.gif

核心思想如下:

  • 定时切换数据
  • 在颜色上,每页或者每屏的颜色一定要互相取反

核心代码如下:

import { useState, useEffect } from 'react';
import { Table } from 'antd';
const data1 = [...];
const data2 = [...];
const data3 = [...];
function App (){
    const [dataSource, setDataSource] = useState(data1);
    const [column, setColumn] = useState([...]);
    const [count, setCount] = useState(1);
    
    const setTableRowClass = (record, index) => {
        if (record.key % 2 !== 0){
          return count % 2 !== 0 ? 'one-color' : 'two-color';
        } else {
          return count % 2 !== 0 ? 'two-color' : 'one-color';
        }
    }
    
    const changeTableData = (count) => {
        setDataSource(count === 2 ? data2 : data3);
    }
    
    useEffect(()=>{
        let timer = setInterval(() => {
            count++;
            setCount(count);
            changeTableData(count);
        }, 6000);
        return () => {
          clearInterval(timer);
        }
    });
    
    return <Table column = {column} dataSource = {dataSource} rowClassName = {setTableRowClass}/>
}

2.2、整页翻页效果

通过批量操作高度来达到“翻页”效果,效果如下:

table动画2.gif

核心思想如下:

  • 定时“补充”数据
  • 记录上一页数据行的范围,并将这个范围内的所有数据行的高度都置为0

核心代码如下:

import React from 'react';
import { Table } from 'antd';

const data1 = [...];
const data2 = [...];
const data3 = [...];

const columns = [...];

class App extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            data: data1
        }
        this.count = 1;
    }
    
    newFixedTimeChangeData = (timeout, count) => {
      // 定时补充数据
      this.setState(state => {
        return {
          data: state.data.concat(count === 2 ? data2 : data3)
        }
      }, () => {
        if (document.querySelector('.antd-table-row-item')){
          let arr = Array.from(document.querySelectorAll('.antd-table-row-item'));
          // 记录上一页数据行的范围,并将这个范围内的所有数据行的高度都置为0
          for (let index = (count - 1) * 5 - 5; index < (count - 1) * 5; index++){
            arr[index].classList.add('new-height-antd');
          }
        }
      })
    }
    
    componentDidMount(){
        this.timerInterval = setInterval(() => {
          this.count = this.count + 1;
          this.newFixedTimeChangeData(5000, this.count);
        }, 5000);
    }
    
    render (){
        return <Table column = { column }  dataSource = { this.state.data } />
    }
}

2.3、单行翻页效果

与整页翻页效果不同的是,单行翻页效果每次只将一行数据的高度置为0,效果如下:

table动画3.gif

核心代码如下:

// 其余代码与整页翻滚的代码一样
// animationIndex:记录应该执行翻页效果的数据行的位置
let animationIndex = 0;
newFixedTimeChangeData = (timeout, count) => {
  // 定时补充数据
  this.setState(state => {
    return {
      data: state.data.concat(count === 2 ? data2 : data3)
    }
  }, () => {
    if (document.querySelector('.antd-table-row-item')){
      let arr = Array.from(document.querySelectorAll('.antd-table-row-item'));
      arr[animationIndex].classList.add('new-height-antd');
      animationIndex++;
    }
  })
}

2.4、整页滚动效果

这个也是一个常见的效果,效果如下:

table动画4.gif

核心思路:

  • 动态的改变每个tr的transform。

核心代码(react):

import React from 'react';
import { Table } from 'antd';

const column = [...];
const dataSource = [...];

class App extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            dataSource,
            scrollTop: 0
        }
    }
    setTableCssScroll = () => {
        this.setState((state) => {
          return {
            ...state,
            // 每次执行,都向上滚动10px
            scrollTop: state.scrollTop - 10
          }
        }, () => {
          if (document.querySelector('.antd-table-row-item')){
            let arr = Array.from(document.querySelectorAll('.antd-table-row-item'));
            for (let index = 0; index < arr.length; index++){
              // 没行都向上10px
              arr[index].style.transform = `translateY(${this.state.scrollTop}px)`
            }
          }
        });
    }
    componentDidMount(){
        this.timerInterval = setInterval(() => {
          this.setTableCssScroll();
        }, 3000);
    }
    render (){
        return <Table column = { column } dataSource = { dataSource }>
    }
}

核心代码(css)

// 否则向上transformtr会与表头重合
.ant-table-thead th {
  z-index: 999;
}

三、实际项目中还应该思考的点

大家其实会发现,上面的方案中,所有的数据都是模拟的,根本没有与后端进行交互。所以我认为,在实际项目中,我们至少还应该考虑以下几点:

  • 如果数据到了最后一屏 or 数据总量小于一屏,是否还需要执行滚动效果?
  • 数据如果过多,应该要保证dom节点数量固定,防止浏览器崩溃。(这里给大家一个思路,data正常维护,但是删除dom一定要原生删除)
  • 数据请求的时机。(以整页翻滚为例,每页翻滚前都要请求一遍数据,防止前一页与下一页之间出现空隙)

四、最后

好啦,又到了结尾了,如果大家还有什么好的方案并且这篇文章里没有讲到的,欢迎大家补充。还有第三点里要思考的点里,我并没有给出相应的代码(我虽然在项目里解决了上述的问题,但是我认为并不是最优解,所以没有在文章里体现),如果大家有好的方法,也欢迎评论区里补充。