marquee将被官方遗弃?教你如何手写实现marquee文字跑马灯!

1,223 阅读1分钟

前言

今天有接到一个新的需求,老大说想要那种文字跑马灯的效果,我一下就答应下来,这不简单么!一个标签不就直接解决么!

1.gif

我直接打开我的vscode 输入了一个marquee 标签 运行启动,简直完美!

2.jpg

突然,我灵光一现,打开了w3school 查找 marquee ,好家伙 直接查不到

3.png 因为想起来网上说marquee标签即将被弃用 而且我做的项目还是electron 内嵌vue 打包成安卓的项目 更可能会有兼容性问题 所以看来不能直接用 marquee标签,于是我开始钻研如何手写marquee 标签 下面我将用css 方式js 方式 来实现文字跑马灯的效果!

css 方式实现marquee

html:
<div class="marquee">
    <p>这里是滚动的文字,就和广告滚动一样的效果,懂得都懂</p>
</div>
css:
.marquee {
    width: 450px;
    line-height: 50px;
    background-color: red;
    color: white;
    white-space: nowrap;
    overflow: hidden;
    box-sizing: border-box;
}
.marquee p {
    display: inline-block;
    padding-left: 100%;
    animation: marquee 15s linear infinite;
}
@keyframes marquee {
    0%   { transform: translate(0, 0); }
    100% { transform: translate(-100%, 0); }
}
效果

4.gif

缺点

css 方式的缺点也很明显 无法实现跑马灯的速度的控制以及鼠标悬浮文字停下等等一些复杂的功能实现都比较麻烦

js (vue)方式实现marquee

<template>
  <div class="vue-marquee">
    <slot></slot>
    <div class="vue-marquee-wrapper" ref="wrap">
      <div
        class="vue-marquee-text"
        ref="text"
        @click="$emit('click')"
        @mouseover="mouseOver && stopRoll()"
        @mouseout="mouseOver && continueRoll()"
        :style="{ left: textLeft, transition: textTransition, cursor }"
      >
        {{ text }}
      </div>
    </div>
  </div>
</template>

<script>
module.exports = {
  name: 'VueMarquee',
  data() {
    return {
      textLeft: '',
      textTransition: '',
      timer: null,
    };
  },
  props: {
    text: {
      type: String,
      default: ''
    },
    // 滚动时间(单位: ms)
    rollTime: {
      type: Number,
      default: 12000
    },
    cursor: {
      type: String,
      default: 'text'
    },
    mouseOver: {
      type: Boolean,
      default: true
    }
  },
  watch: {
    // 监听文本变化重新运作
    text: {
      handler() {
        this.reset();
      },
    },
    // 监听滚动时间变化
    rollTime: {
      handler() {
        this.reset();
      },
    },
  },
  mounted() {
    this.marquee();
  },
  methods: {
    // 跑马灯运作
    marquee() {
      if (this.text === '') return;
      this.textRoll();
    },
    // 文本滚动
    textRoll() {
      const wrapWidth = this.$refs.wrap.clientWidth;
      const textLeft = this.$refs.text.offsetLeft;
      const textWidth = this.$refs.text.clientWidth;
      // 暂停/开始滚动时需要判断当前文本滚动的进度
      const rollTime = this.rollTime * ((textLeft + textWidth) / (wrapWidth + textWidth));
      const againTime = rollTime + 500; // 重新开始滚动时间计算
      this.textTransition = `left ${rollTime}ms linear`; // 滚动前绑定过渡属性
      setTimeout(() => { this.textLeft = `-${textWidth}px`; }); // 向容器最左移动
      this.timer = setTimeout(() => {
        this.reset()
      }, againTime);
    },
    // 停止滚动
    stopRoll() {
      clearTimeout(this.timer);
      this.textLeft = `${this.$refs.text.offsetLeft}px`;
    },
    // 继续滚动
    continueRoll() {
      clearTimeout(this.timer);
      this.textRoll();
    },
    // 重置
    reset() {
      clearTimeout(this.timer);
      // 还原文本位置
      this.textTransition = 'none'; // 还原前需清除过渡
      this.textLeft = '100%';
      setTimeout(() => { this.textRoll(); });
    }
  },
  beforeDestory() {
    clearTimeout(this.timer);
  }
};
</script>

<style scoped>
.vue-marquee {
  display: flex;
  align-items: center;
  height: 100%;
}

.vue-marquee-wrapper {
  display: flex;
  align-items: center;
  flex: 1;
  height: 100%;
  overflow: hidden;
  position: relative;
}

/* .vue-marquee img {
  width: 14px;
  height: 12px;
  margin-right: 7px;
} */

.vue-marquee-text {
  white-space: nowrap;
  position: absolute;
  left: 100%;
}

</style>

上面的方式 使用了插件vue-marque 但是因为和我项目有点出入 所以我就改了源码变成自己所需要的方式,如果有更好的方式 欢迎一起讨论学习