前言
最近因为工作需要得整个滚动播放的公告栏,上网找了一会儿也没找到什么合适的,故开始琢磨还有没有其他方法实现这个功能。
这里先贴一下网上传的比较广的方法(样式就不贴了,大同小异):
<template>
<div class="wrap">
<div ref="box" class="box">
<div ref="marquee" class="marquee">{{text}}</div>
<div ref="copy" class="copy"></div>
</div>
<div ref="node" class="node">{{text}}</div>
</div>
</template>
<script>
export default {
name : 'Marquee',
props: ['lists'], // 父组件传入数据, 数组形式 [ "连雨不知春去","一晴方觉夏深"]
data () {
return {
text: '' // 数组文字转化后的字符串
}
},
methods: {
move () {
// 获取文字text 的计算后宽度 (由于overflow的存在,直接获取不到,需要独立的node计算)
let width = this.$refs.node.getBoundingClientRect().width
this.$refs.copy.innerText = this.text // 文字副本填充
let distance = 0 // 位移距离
// 设置位移
setInterval(() => {
distance = distance - 1
// 如果位移超过文字宽度,则回到起点
if (-distance >= width) {
distance = 16
}
this.$refs.box.style.transform = 'translateX(' + distance + 'px)'
}, 20)
}
},
// 把父组件传入的arr转化成字符串
mounted: function () {
for (let i = 0; i < this.lists.length; i++) {
this.text += ' ' + this.lists[i]
}
},
// 更新的时候运动
updated: function () {
this.move()
}
}
</script>
大致思路就是用两个相同的内容,每隔20ms向X轴负方向移动1px,通过滚动播放以达到这段文字首尾相接的显示效果。
既然首尾相接的效果是通过两条相同内容达到,而且动画的效果并不复杂,那换一种思路应该也可以实现,于是我想到了CSS动画---“丝般顺滑”。
通过CSS动画实现该效果
先贴代码(无关的样式就不贴了):
<template>
<div>
<div class="rollWrapper">
<div class="textItem">
<span class="textContent" :style="{width:stringLength+'px'}">{{text}}</span>
<span class="textContent" ref="node">{{text}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'roll',
data() {
return {
text: "幸福,往往是摸得透澈,而堇业的心却常常隐藏。",
stringLength:"",
}
},
methods: {
addKeyframesRule() {
let ss = document.styleSheets,
rule, i, x;
for (i = ss.length-1; i >= 0; --i) {
if (ss[i].cssRules) {
for (x = ss[i].cssRules.length - 1; x >= 0; x--) {
rule = ss[i].cssRules[x];
if(rule.name && rule.name.includes('textScroll') && rule.type === 7){
rule.appendRule('to {transform: translateX(-' + this.stringLength + 'px);}');
return rule;
}
}
}
}
return null
},
},
mounted() {
this.stringLength = String(this.$refs.node.getBoundingClientRect().width)
this.addKeyframesRule()
}
}
</script>
<style scoped>
.textContent{
/* 此处的padding是为了达到无缝切换的效果,不加导致的问题我说不太清,大伙可以试试 */
padding-right: 320px;
}
.textItem {
animation: textScroll linear 15s infinite;
}
@keyframes textScroll {
from {
transform: translateX(0)
}
/*to的内容由方法赋予*/
}
</style>
思路很简单,这里直接说重点:获取text
中文本的长度赋予stringLength
后,通过动画名寻找并使用stringLength
补全关键帧缺失的to{}
(或者说是100%{}
)内容,完成css动画(当然也支持hover暂停= =)。
然后首尾相连的滚动文本框就简简单单的完成了(可以应付多数情况,当然存在的问题也不少)。
预览:
相比开头方法的优缺点
优点
优点没什么特别能说的,就是单纯的css动画的优点,比如能够被浏览器优化、能够使用硬件提升性能这种,反正就是丝滑。
缺点
缺点包括但不限于组件本身的一些bug(比如代码中提到的需要一个padding)
除此之外比较要命的一点是:在text的内容不固定时,stringLength
的值也会动态变化,而动画的持续时间是不会变的---也就是说如果文本内容突然变得很长或/很短,滚动的速度就会相应变得很快/很慢。(当然也可以通过跟上面相似的方法修改动画的持续时间,但那么麻烦的话还不如就用js动画算了= =)
写点别的
因为我本来也是个小白,对于实现功能的思路还比较欠缺,不过现在这个写法又能满足需求代码量又少,所以就记录一下,这种简单文本滚动播放的组件以后说不定还能用得到,到时候再来贴一份。。。
= w = 感谢你能看到这里,如果能成为谁的参考,我就不算白码这点字,当然如果有幸帮上了谁的忙,那就是最值得我高兴的事情了。
工作固然重要,不过一定要持续学习。
生活可以很艰苦,但永远不要让好奇心蒙尘。