首页 > 技术文章 > 前端文字跑马灯

KlllB 2020-06-12 17:35 原文

最近接到一个新任务,开发的页面中有文字滚动显示的需求,因为是个小项目,就想自己用原生js来实现,既可以做一点有趣的原创,也可以减少引入插件的代码量。

一开始我是想使用css来实现的,这样就能把性能开销降到最低。

我的思路是,使用2个容器,外层容器作为展示区,内层容器作为文本载体,这样只需要循环地从右向左移动内层的文本载体就可以实现了。

因为要不断重复这个滚动的过程,所以我是用了css动画来实现,具体思路是将内层容器的开始状态设置为transform:translate(100%,0),然后将结束状态设置为transform:translate(-100%,0)就行了。经过测试发现一个问题:如果内层文本使用行内标签,transform是无法生效的,所以只能使用块级标签,那么内层的块级标签的宽度就会和外层容器一样大,此时,如果内层容器的内容实际长度小于标签的长度,那么内层标签空白区域的滚动过程对于用户体验来说是非常差的。

于是我想把内部容器的宽度缩小到实际宽度,是不是可以解决问题呢?

给内层容器加上width:fit-content属性,可以解决空白区域的问题,但是又带来了一个新的问题,就是transform:translate(100%,0)是将元素向右移动本身的宽度,在内层容器宽度小于外层容器宽度的情况下,内部容器每次向左滚动的起点就不是外层容器的最右边了。所以这样做是不行的。

然后我又考虑使用相对定位/绝对定位来做起始和结束的状态,因为相对定位/绝对定位的left,right使用百分比作为值,它是基于父元素的宽度而言的,将开始状态设为right:-100%,结束状态设置为right:100%,但是这样一来,内部容器最终会移动到外部容器左边外部100%宽度的地方,内部容器宽度小于外部容器还是会固定移动空白的距离,如果内部容器长度大于外部容器,内部容器就不能全部移动到外部容器外面了。

于是我决定放弃css,还是改用js来进行实现。

首先要确定内部容的开始位置与结束位置,开始位置:内部容器的最左边应该在外部容器的最右边外,结束位置:内部容器的最右边应该在外部容器的最左边外

开始位置很容易实现,只要把内部容器向右移动外部容器宽度的距离即可。结束位置就比较难判断了,因为内部容易的宽度是不确定的。考察了dom元素盒模型的位置后,发现通过offsetLeft可以确定子元素与父元素的位置:offsetLeft是子元素左边框到父元素左边框的距离,子元素左边框在父元素左边框的右边为正数,在父元素的左边为负数,只要内部容器的offsetLeft小于内部容器宽度的负数,那么就说明整个内部容器都消失在外部容器的可视范围,就是结束位置了,此时把内部容器的位置更改为开始位置即可进行下一轮滚动,这里说明一下为什么不比较offsetLeft的绝对值和内部容器的宽度,因为初始位置,内部容器是在外部容器的右边,此时offsetLeft就是外部容器的宽度,如果内部容器宽度小于外部容器,那么也会被判断为结束位置。

因为是向左滚动,所以初始状态就设为left:100%,然后使用setInterval循环比较内部容器offsetLeft和内部容器宽度的负数,如果offsetLeft > -宽度,那么设置内部容器的left-1,否则就设置内部容器的left为100%,重置为初始位置。

代码比较简单,我就不贴上来了,只要逻辑理通顺了,很容易就能写出来。

 

推荐阅读