需求场景:Vue2实现一个文本滚动的效果,超出固定宽度就无限循环的滚动,时间随文本长度变化而变化
效果如下:
需要考虑的点:
- 1.滚动的效果怎么做
- 2.什么时候该滚动,什么时候不滚动
- 3.长文本和短文本的滚动时间肯定不能一样,这个时间怎么定
刚接到需求,因为在此之前看过一篇博文,大致是前段时间在工位装摄像头的事件,掘金有篇敢在我工位装摄像头,吃我一记组合拳的文章,里面取巧用到了css原生的文本滚动效果,在电脑屏幕上滚动着老板看了兴奋不已的打工人激励文字,就想着应该还简单,没想到自己实现起来,却吃了大亏。
1.效果实现
这个刚开始肯定没头绪,先是一顿百度,找了个感觉靠谱的,一顿CV,发现不好使,然后不得不重头开始读他的想法,下面贴个我的代码吧。
大致就是给要滚动的元素的父级盒子 添加个overflow: hidden;
,然后给要滚动的元素添加上滚动动画,不换行,执行xx秒(animation: 10s linear infinite;),然后写个过渡动画,如果只有一个滚动的话,到这就完事了。
<div class="page-text-title">原告:</div>
<div class="scroll">
<div class="scroll-cartoon" v-if="isLinePlaintiff"
:style="{ animationDuration: getAnimationDuration(getParty(0)) }">
{{ getParty(0) }}
</div>
</div>
@keyframes scroll-up {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-100%);
}
}
.scroll {
overflow: hidden;
}
.scroll-cartoon {
animation: scroll-up linear infinite;
white-space: nowrap;
}
在这过程中,出现了很多闹心的css样式问题,滚过头覆盖title了或不滚动了,控制台多审查审查。
2.滚动时机
单个的滚动做完了,可这只是考虑了文本超长的情况,正常情况呢,这时候应该不滚动的。
前期我想根据字符传长度判断是否滚动,发现宽度给定时,全数字,全中文含符号,以及中英文混杂的情况的长度都不一样,也就不好区分一个度,这样做可能会出现,长度明明够容下一样却出现了滚动的效果。考虑过后放弃了该想法。
后面我就想通过是否换行来判断,这样不就解决了。当时确实是猪脑过载了,居然想着拿页面元素的宽度来判断,试了好一会,发现无论怎么百度怎么取,拿到的长度跟我我页面审查的不一样。一阵顿悟发现,还是判断高度比较好使,另外注意获取时机,应当在挂载后获取,而不是傻傻的在mounted阶段拿。
在元素上绑定ref,或者你直接通过document.getelementbyid('')也行,取到元素在页面实际的高度,以此来判断是否该执行动画。
const fields = {
cipher: 'isLine',
plaintiff: 'isLinePlaintiff',
defendant: 'isLineDefendant'
};
this.$nextTick(() => {
// 判断是否换行,换行则说明宽度大于最长字符,那就实施滚动动画
Object.keys(fields).forEach(fieldName => {
if (this.$refs[fieldName].scrollHeight > 36) {
this[fields[fieldName]] = true;
}
});
});
3.利用scss配置动态滚动时间
由于我这文本滚动长度不一,滚动动画虽然是公用一套,但时间肯定不能写死。写多几套动画适配虽然能行,但我还是想通过变量的方式实现。
变量依据 animation-duration
实现。
实现大致方式:动画时间用变量接收,那我就得写一个方法返回这个变量,这个方法由需要的元素调用即可。
在style里传入文本大小,计算动画时间,这里取巧,采用了 Math.min/max 对文本长度与时间关系,然后取极值的方式,个人感觉比较靠谱。
<template>
<div class="wrapper">
<div class="scroll-up" :style="{ animationDuration: getAnimationDuration(text1) }">...</div>
<div class="scroll-up" :style="{ animationDuration: getAnimationDuration(text2) }">...</div>
</div>
</template>
<script>
export default {
data() {
return {
text1: '',
text2: ''
};
},
methods: {
getAnimationDuration(text) {
if (!text) {
return '8s';
}
const textLength = text.length;
const minDuration = 10;
const maxDuration = 45;
const duration = Math.min(Math.max(textLength / 5, minDuration), maxDuration);
return `${duration}s`;
}
},
mounted() {
// 模拟接口数据
setTimeout(() => {
this.text1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
this.text2 = 'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
}, 2000);
}
};
</script>
<style lang="scss">
.scroll-up {
animation: scroll-up linear infinite;
overflow: hidden;
white-space: nowrap;
}
@keyframes scroll-up {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
</style>
这小需求就到这吧,后期产品有啥天马行空的想法了,我看看再怎么满足ta。