一个小文本滚动引发的思考

445 阅读3分钟

需求场景:Vue2实现一个文本滚动的效果,超出固定宽度就无限循环的滚动,时间随文本长度变化而变化

效果如下:

动画.gif

需要考虑的点:

  • 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。