react前端滚动组件

滚动组件分享(react)

前一段时间一直有大屏相关的业务需求,大屏嘛,顾名思义,花里胡哨,华而不实(bushi,我发现甲方爸爸特别喜欢滚来滚去的列表展示样式,基本上每个界面都要有个滚动列表,要首尾衔接滚动,要丝滑,要自动配界面巴拉巴拉…之前刷到过的都是定义两个定时器,看着很复杂,看不懂,干脆自己写个算了,周末闲来无事,试试就逝世。

功能点

支持自定义滚动样式,包括首尾衔接滚动,来回滚动(向下滚到底后向上滚动),滚动速度等

代码

组件本身代码:

/**
* @effect: 滚动组件,支持来回滚动
* @Date:2023-02-25 16:25:45
*/
import React, { useState, useEffect } from 'react';
import './index.less';
import _ from 'lodash';

const CycleShow=(props)=> {
    const { styles, children, viewHeight, itemHeight, speed, listLength = children.props.children.length, isNoseToTail,  moveHeight = itemHeight * listLength - viewHeight } = props;
    const [cycleStart, setcycleStart] = useState(0);
    let timer = null;
    let chushu = isNoseToTail ? (((moveHeight * 2) / speed) + ( 50 / speed)) : ((moveHeight * 2) / speed);

    const _running = (value) => {
        value = value + 1;
        let tmp = value % chushu;
        setcycleStart(tmp);
        timer = requestAnimationFrame(() => { _running(tmp); });
    };

    useEffect(() => {
        _running(1);
        return () => {
            timer && cancelAnimationFrame(timer);
        };
    }, []);

	//	如果是首尾相连滚动,渲染两次防止出现空白区域
    return (
        <div className="cycleShow-wrapper" style={{ ...styles }}>
            {isNoseToTail
                ?
                <div className="noseTail-show"
                    style={
                        { transform: `translateY(${-cycleStart * speed}px)` }
                    }
                >
                    {children}
                    {children}
                </div>
                :
                <div className="rollBack-show"
                    style={
                        cycleStart > ((moveHeight / speed) - 1) ?
                            { transform: `translateY(${cycleStart * speed - (moveHeight * 2)}px)` } :
                            { transform: `translateY(${-cycleStart * speed}px)` }
                    }
                >
                    {children}
                </div>}
        </div >
    );
}

export default CycleShow;

其中,requestAnimationFrame()方法是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。
但与setTimeout相比,requestAnimationFrame最大的优势是由浏览器来决定回调函数的执行机制,如果屏幕刷新频率是60Hz,那么回调函数每秒执行60次,如果屏幕刷新率是75Hz,那么回调函数每秒执行75次。这样可以保证回调函数在屏幕每一次的刷新间隔中只被执行一次,不会导致动画卡顿了。并且,当页面被隐藏或者最小化时,绘制任务会被浏览器暂停,requestAnimationFrame也会停止渲染,而setTimeout仍会执行动画任务,造成资源浪费。
requestAnimationFrame是有返回值的,返回一个整数,表示请求id。可以将此id传给cancelAnimationFrame()来取消该请求方法。
使用该组件时,需要传递一些参数:

名称描述是否必须
styles自定义的样式非必须
children滚动的的内容,可以是表格,可以是其他的,完全支持自定义必须,传递的内容需要用Fragment将元素包裹起来
viewHeight视区高度,即滚动元素的整体高度必须
itemHeight滚动的单个元素的高度必须
speed滚动速度:每秒滚动多少px非必须,不传默认0.5
isNoseToTail滚动样式:true:首尾相连 false:从头到尾从尾到头非必须

eg:

import React, { useState, useEffect, useRef, Fragment } from 'react';
import './index.less';
import CycleShow from '.';
import './cycleShow.less'
const defaultData = [{
    id: 1,
    name: '阿瓜1',
    age: '18'
}, {
    id: 2,
    name: '阿瓜瓜2',
    age: '18'
}, {
    id: 3,
    name: '阿瓜瓜瓜3',
    age: '18'
}, {
    id: 4,
    name: '阿瓜瓜瓜4',
    age: '18'
}, {
    id: 5,
    name: '阿瓜瓜瓜5',
    age: '18'
}, {
    id: 6,
    name: '阿瓜瓜瓜6',
    age: '18'
}
]

const ITEM_HEIGHT = 40;
const Test = (props) => {
    const _randerChildren = () => {
        return <Fragment>
            {defaultData.map((item, idx) => {
                return <div style={{ height: `${ITEM_HEIGHT}px` }} key={item.id} className={"item"}>{item.name}</div>
            })}
        </Fragment>
    }
    return (
        <div className="test-wrapper" >
            <CycleShow
                isNoseToTail  //滚动类型 true:首尾相连  false:从头到尾从尾到头
                children={_randerChildren()} //子元素dom --必传
                viewHeight={100} //视区高度,单位是px  --必传
                itemHeight={ITEM_HEIGHT} //每行元素的高度 --必传,建议viewHeight是itemHeight的倍数
            	speed={0.5}  //滚动速度,即1000/60毫秒移动多少px
            />
        </div>
    );
}
export default Test;

最终效果:(感觉这个动图录制软件有点失帧,实际上比较流畅)
请添加图片描述
最后:记得样式文件中将超出隐藏起来哈:overflow: hidden;

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值