多条文字切换滚动实现(React、JS)

时间:2021-2-20 作者:admin

一、需求

1、一条或者多条滚动文字,有序切换
2、循环滚动

二、原理

setInterval:控制循环
requestAnimationFrame:动画效果

三、实现

 constructor() {
    super();
    this.state = {
        sloganList: [
            "横向滚动文字1横向滚动文字1横向滚动文字1横向滚动文字1",
            "横向滚动文字2",
            "横向滚动文字3",
        ],
        sloganIndex: 0,//展示的文本下标
    }
    this.sign = true;//定时器判断是否要进行文字滚动动画
    this.textWidth = 0;//文字的宽度
    this.textLeft = 0;
    this.offsetStep = 3;//每次移动的步长
}

constructor内部主要记录了滚动文字的基本信息,重要的两个参数是sloganIndex,sign。
sloganIndex控制目前需要展示的数据下标
sign则是判断是否调用文字滚动控制方法,值为true则调用,进入新一轮的滚动动画

componentDidMount() {
    let sloganContainer = this.container.clientWidth;
    this.text.style.left = sloganContainer + "px";
    this.timer = setInterval(() => {
        if (this.sign) {
            if(Array.isArray(this.state.sloganList)&&this.state.sloganList.length) {
                this.showSlogan();
            } else {
                clearInterval(this.timer);
            }
        } else {
            this.timer = null;
        }
    }, 1000);
}

componentWillUnmount() {
    clearInterval(this.timer);
}

在组建渲染完成后定时器启动,通过sign信号控制是否执行滚动方法;组件销毁、数据格式错误或是没有数据时清除定时器

showSlogan = () => {
    this.textWidth = this.text.clientWidth;//文字宽度
    this.textLeft = parseInt(this.text.style.left);//相对父元素偏移距离
    if(this.textLeft >= -this.textWidth) this.sign = false;
    if(this.textLeft > -this.textWidth) {
        this.text.style.left = this.textLeft - this.offsetStep + "px";
        requestAnimationFrame(this.showSlogan)
    } else {
        let nextIndex = 
        this.state.sloganIndex != this.state.sloganList.length - 1 ? ++this.state.sloganIndex : 0;
        this.setState({
            sloganIndex: nextIndex
        }, () => {
            this.text.style.left = this.container.clientWidth + "px";
            this.textWidth = this.text.clientWidth;
            this.sign = true;
        })
    }
}

1、开始滚动前,将sign设置为false,滚动期间不会重复调用
2、文字直到最后一个字消失本次任务才算结束,所以文字元素最后的left值为元素宽度的负值
3、本轮动画结束后判断下一个动画文字所在下标,改变sloganIndex
4、待新内容渲染结束后设置新文字元素在内容区的最右边,并获取新的滚动文字宽度
5、设置sign为true,定时器运行时检查到该值为true则调用showSlogan方法

四、完整代码

class Slogan extends Component {
    constructor() {
        super();
        this.state = {
            sloganList: [
                "横向滚动文字1横向滚动文字1横向滚动文字1横向滚动文字1",
                "横向滚动文字2",
                "横向滚动文字3",
            ],
            sloganIndex: 0,
        }
        this.sign = true;//判断是否进行文字滚动动画
        this.textWidth = 0;//文字的宽度
        this.textLeft = 0;
        this.offsetStep = 3;//每次移动的步长
    }

    componentDidMount() {
        let sloganContainer = this.container.clientWidth;
        this.text.style.left = sloganContainer + "px";
        this.timer = setInterval(() => {
            if (this.sign) {
                if(this.state.sloganList&&this.state.sloganList.length) {
                    this.showSlogan();
                } else {
                    clearInterval(this.timer);
                }
            } else {
                this.timer = null;
            }
        }, 1000);
    }

    componentWillUnmount() {
        clearInterval(this.timer);
    }

    render() {
        const { sloganList, sloganIndex } = this.state;
        return (
            <div ref={(ref) => this.container = ref} className="container">
                <span ref={(ref) => this.text = ref} className="slogan">
                    {sloganList[sloganIndex]}
                </span>
            </div>
        )
    }

    showSlogan = () => {
        this.textWidth = this.text.clientWidth;//文字宽度
        this.textLeft = parseInt(this.text.style.left);//相对父元素偏移距离
        if(this.textLeft >= -this.textWidth) this.sign = false;
        if(this.textLeft > -this.textWidth) {
            this.text.style.left = this.textLeft - this.offsetStep + "px";
            requestAnimationFrame(this.showSlogan)
        } else {
            let nextIndex = this.state.sloganIndex != this.state.sloganList.length - 1 ? ++this.state.sloganIndex : 0;
            this.setState({
                sloganIndex: nextIndex
            }, () => {
                this.text.style.left = this.container.clientWidth + "px";
                this.textWidth = this.text.clientWidth;
                this.sign = true;
            })
        }
    }
}
.container {
    width: 70%;
    height: 35px;
    line-height: 35px;
    margin: 0 auto;
    border: 1px solid #B0BEC5;
    padding: 0 10px;
    position: relative;
    overflow: hidden;
}

.slogan {
    position: relative;
    display: inline-block;
}

五、总结

主要做个记录,也没用jQuery,原生js的getter/setter操作太麻烦了
希望互相学习,非常感谢。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。