Articles19
Tags0
Categories0

无限垂直滚动组件

无限垂直组件

1.数据:

const formData = {
  tableHead: [
    '国家',
    '买家公司',
    '价格条款',
    '金额',
    '申请出口时间'
  ],
  tableData: [
    {
      id: 0,
      country: '美国',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 1,
      country: '英国',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 2,
      country: '意大利',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 3,
      country: '德国',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 4,
      country: '澳大利亚',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 5,
      country: '韩国',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 6,
      country: '日本',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 7,
      country: '阿鲁巴',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 8,
      country: '越南',
      company: 'sssa',
      price_term: 'FFF',
      amount: 720000,
      time: '2019-01-01'
    },
    {
      id: 9,
      country: '日本',
      company: 'kkll',
      price_term: 'FFF',
      amount: 920000,
      time: '2019-01-01'
    },
    {
      id: 10,
      country: '阿鲁巴',
      company: 'seig',
      price_term: 'FFF',
      amount: 820000,
      time: '2019-01-01'
    },
    {
      id: 11,
      country: '越南',
      company: 'ee*h',
      price_term: 'FFF',
      amount: 620000,
      time: '2019-01-01'
    },
  ]
}
export default formData

2.less文件

.formBox{
  /* width: auto; */
  height: 500px;
  color: white;
  background:#2b2e3d;
  border-radius: 2px;
  &__title{
    padding-top:20px;
    padding-left:20px;
    font-size: 20px;
    font-weight: 600;
    color: white;
    line-height: 40px;
 }
 &__table{
   width:95%;
   line-height: 40px;
   margin: 0 auto;
   &--head{
     display: flex;
     flex-direction: row;
     border-bottom: 1px solid white;
   div{
     width: 100px;
     text-align: center;
   }
   }
   &--contain{
    display: flex;
    flex-direction: row;
    div{
      width: 100px;
      text-align: center;
    }
   }
 }
}

.datalist{

  height:280px;
   overflow: hidden;



}
.notrans{
  position: relative;


}
.trans{
  position: relative;
  transition: all 1s ease 1s;
}

3.具体实现

无动画效果

/* eslint-disable react/destructuring-assignment */
import React from 'react'
import styles from './InfinteVerticalScroll.less'

/*
props:dataSource:{
  tableHead:表头数据
  tableData:表单数据
}
speed:垂直滚动速度
title:表格标题
delay:延时
direction:方向 up|down
*/
let tt
// const { tableHead, tableData } = testData
class InfinteVerticalScroll extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      tableData_data: this.props.dataSource.tableData,
      isArea: false,
    }
    this.refList = React.createRef()
  }

  componentDidMount() {
    console.log('-------------------')
    console.log(this.refList)
    console.log('-------------------')
    this.scrollData()
    document.addEventListener('mouseover', this.handleMοuseOver, false)
  }

  componentWillUnmount() {
    document.removeEventListener('mouseover', this.handleMοuseOver, false)
  }

  handleMοuseOver = (event) => {
    if (this.node.contains(event.target)) {
      this.setState({
        isArea: true
      })
      clearInterval(tt)
      return
    }
    if (this.state.isArea) {
      this.setState({
        isArea: false
      })
      this.debounce(this.scrollData(), 3000)
    }
  }

  scrollData = () => {
    const { speed, dataSource } = this.props
    const { tableData } = dataSource
    if (this.state.isArea === false) {
      clearInterval(tt)
      tt = setInterval(() => {
        const newData = tableData.pop()

        tableData.unshift(newData)

        this.setState({
          tableData_data: tableData
        })
        if (this.state.isArea) {
          clearInterval(tt)
        }
      }, speed * 1000);
      if (this.state.isArea) {
        clearInterval(tt)
      }
    }
  }

  handleChangeData = () => {
  }

  debounce = (fn, delay) => {
    let timerId;
    return (...args) => {
      if (timerId) {
        clearInterval(timerId)
      }
      timerId = setTimeout(() => {
        fn(...args);
        timerId = null;
      }, delay)
    }
  }

  handleStop = () => {
    this.setState({
      isArea: true
    })
    clearInterval(tt)
  }

  render() {
    const { tableData_data } = this.state
    const { dataSource, title } = this.props
    const { tableHead } = dataSource
    const arr = []
    let count = 0
    // eslint-disable-next-line no-restricted-syntax
    for (const x in tableData_data[0]) {
      if (x !== 'id') {
        arr[count += 1] = x
      }
    }
    const formattableHeadData = (datasource) => datasource.map((item, index) => Object.assign(item, { id: index, data: item }))
    return (

      <div
        className={styles.formBox}
        ref={(ref) => { this.node = ref }}
        onMouseOver={this.handleChangeData}
        onFocus={this.handleStop}
      >
        <h5 className={styles.formBoxTitle}>{title}</h5>
        <div className={styles.formBoxTable}>
          <div className={styles.formBoxTableHead}>
            {formattableHeadData(tableHead).map((item) => (
              <div key={item.id}>{item.data}</div>
            )
            )}
          </div>
          <div>
          {tableData_data.map((item) => (
            <div className={styles.formBoxTableContain} key={item.id} ref={this.refList}>
              {formattableHeadData(arr).map((item_i) => (
                <div key={item_i.id}>{item[item_i.data]}</div>
              ))}
            </div>
          ))}
          </div>
        </div>

      </div>

    )
  }
}
export default InfinteVerticalScroll

有动画效果

/* eslint-disable react/destructuring-assignment */

import React from 'react'
import styles from './InfinteVerticalScroll.less'

/*
props:dataSource:{
  tableHead:表头数据
  tableData:表单数据
}
speed:垂直滚动速度,默认2s
title:表格标题
delay:延时,默认2s
direction:方向 up|down 默认down
*/

let scrollInterval

// const { tableHead, tableData } = testData

class NewTry extends React.Component {
  constructor(props) {
    super(props)
    this.state = ({
      tableData_data: this.props.dataSource.tableData,
      listMarginTop: '-40px',
      trans: true,
      istimeOut: true
    })
  }

  componentDidMount() {
    this.handleScroll()
  }

  handleStop = () => {
    clearInterval(scrollInterval)
  }


  // handleDownScroll = () => {
  //   this.handleStop();
  //   this.scrollDowm();
  //   scrollInterval = setInterval(this.scrollDowm, 3000)

  // }

  // handleUpScroll = () => {
  //   this.handleStop()
  //   this.scrollUp()
  //   scrollInterval = setInterval(this.scrollUp, 3000)
  // }

  // scrollDowm = () => {
  //   const { tableData_data } = this.state;
  //   this.setState({
  //     trans: true,
  //     listMarginTop: '0px'
  //   });
  //   setTimeout(() => {
  //     tableData_data.unshift(tableData_data[tableData_data.length - 1])
  //     tableData_data.pop();
  //     this.setState({
  //       trans: false,
  //       tableData_data,
  //       listMarginTop: '-40px',
  //     })
  //     // this.forceUpdate()
  //   }, 2000)

  // }

  // scrollUp = () => {
  //   const { tableData_data } = this.state;
  //   const data = tableData_data
  //   this.setState({
  //     trans: true,
  //     listMarginTop: '-80px',
  //     tableData_data: data
  //   })
  //   setTimeout(() => {
  //     const data2 = tableData_data
  //     data2.push(this.state.tableData_data[0])
  //     data2.shift();
  //     this.setState({
  //       trans: false,
  //       tableData_data: data2,
  //       listMarginTop: '-40px'
  //     })
  //   }, 2000)
  // }
  handleScroll = () => {
    const { speed = 2 } = this.props
    this.handleStop()
    this.scrollMethod()
    scrollInterval = setInterval(this.scrollMethod, speed * 1000)
  }

  scrollMethod = () => {
    const { direction, delay = 2 } = this.props
    const { tableData_data } = this.state;
    const moveSpace = direction === 'up' ? '-80px' : '0px'
    this.setState({
      trans: true,
      listMarginTop: moveSpace,
    })
    setTimeout(() => {
      if (direction === 'up') {
        tableData_data.push(this.state.tableData_data[0])
        tableData_data.shift();
      } else {
        tableData_data.unshift(tableData_data[tableData_data.length - 1])
        tableData_data.pop();
      }
      this.setState({
        trans: false,
        tableData_data,
        listMarginTop: '-40px'
      })
    }, delay * 1000)
  }


  handleMouseIn = () => {
    this.handleStop()

  }


  handleMouseLeave = () => {
    if (this.state.istimeOut) {
      this.setState({
        istimeOut: false
      }, () => {
        setTimeout(this.setTime, 2000)
        // this.handleLeave()
      })

    }
  }

  setTime = () => {
    if (!this.setState.istimeOut) {
      this.setState({
        istimeOut: true
      })
      this.handleScroll()
    }
  }

  render() {
    const { tableData_data } = this.state
    const { dataSource, title } = this.props
    const { tableHead } = dataSource
    const arr = []
    let count = 0
    const csty = this.state.trans ? styles.trans : styles.notrans

    // eslint-disable-next-line no-restricted-syntax
    for (const x in tableData_data[0]) {
      if (x !== 'id') {
        arr[count += 1] = x
      }
    }
    const formattableHeadData = (datasource) => datasource.map((item, index) => Object.assign(item, { id: index, data: item }))
    return (

      <div
        className={styles.formBox}
        // ref={(ref) => { this.node = ref }}
        onMouseMove={this.handleStop}
        onFocus={this.handleStop}
        onMouseLeave={this.handleMouseLeave}
      >
        <h5 className={styles.formBoxTitle}>{title}</h5>
        <div className={styles.formBoxTable}>
          <div className={styles.formBoxTableHead}>
            {formattableHeadData(tableHead).map((item) => (
              <div key={item.id}>{item.data}</div>
            )
            )}
          </div>
          <div
            className={styles.datalist}
            id="scrollList"
          >
            <div className={csty} style={{ marginTop: this.state.listMarginTop }}>
              {tableData_data.map((item) => (
                <div className={styles.formBoxTableContain} key={item.id}>
                  {formattableHeadData(arr).map((item_i) => (
                    <div key={item_i.id}>{item[item_i.data]}</div>
                  ))}
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>

    )

  }

}

export default NewTry

应用:

import React from 'react'
import InfinteVerticalScroll from '../../components/InfinteVerticalScroll/InfinteVerticalScroll'
// import Newtry from '../../components/InfinteVerticalScroll/Newtry'
import testData from '../../../testData'

const InfinteScroll =()=>(
  <div>
  <InfinteVerticalScroll dataSource={testData} speed={3} title='最新海关数据' direction='up' delay={2} />
  {/* <Newtry dataSource={testData} speed={3} title='最新海关数据' direction='up' delay={2} /> */}

  </div>
)
export default InfinteScroll

4.关于setInterval的弊端和解决方式

https://www.cnblogs.com/gold404/p/10011675.html

https://blog.csdn.net/runOnWay/article/details/80900437

setInterval如果不及时清除定时器,可能会出现调用速度越来越快的情况

解决方式,用setTimeout代替setInterval

var i=0
function show(){
console.log(i);
i++;
if(i<5){
setTimeout(show,1000)
}
}
show()

上面也就是做了一个setTimeout循环,让setTimeout也可以达到setInterval()无限循环的效果,但是不会出现setInterval()越来越快的问题。

Author:shuo
Link:http://yoursite.com/2019/10/17/无限垂直组件/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可