天天看点

前端实现文字滚动(支持横向、纵向)

1.首先安装dayjs插件(后面唯一id使用)

day.js–一个轻量的处理时间和日期的JavaScript库

npm install dayjs --save
           

2.在main.js中引入dayjs插件插件

import dayjs from 'dayjs';
Vue.prototype.$dayjs = dayjs;
           

3.滚动组件

<template>
  <div 
    :id="id" 
    class="marquee-wrapper">
    <span 
      :style="translate" 
      class="marquee-inside">
      <slot />
    </span>
    <span 
      :class="`marquee-fake ${id}-fake`" 
      :style="fakeTranslate" />
  </div>
</template>

<script>
const FAKE_DOM_INTERVAL = 50;
export default {
  name: 'Marquee',
  props: {
    type: {
      type: String,
      default: 'horizontal' // horizontal(横)  vertical(纵)
    },
    speed: {
      type: Number,
      default: 1
    },
    interval: {
      type: Number,
      default: 50
    }
  },
  data() {
    return {
      id: '',
      timerId: null,
      distance: 0,
      fakeDistance: 0
    };
  },
  computed: {
    translate() {
      const direction = this.type === 'horizontal' ? 'X' : 'Y';
      return {
        transform: `translate${direction}(${this.distance}px)`
      };
    },
    fakeTranslate() {
      const direction = this.type === 'horizontal' ? 'X' : 'Y';
      return {
        transform: `translate${direction}(${this.fakeDistance}px)`
      };
    }
  },
  created() {
    this.id = `marquee-${this.$dayjs().valueOf()}`;
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.timerId && window.clearInterval(this.timerId);
  },
  methods: {
    init() {
      const wrapper = document.getElementById(this.id);
      if (!wrapper) return;
      const inside = wrapper.querySelector('.marquee-inside');
      let wrapperOffset;
      let insideOffset;
      if (this.type === 'horizontal') {
        wrapperOffset = wrapper.offsetWidth;
        insideOffset = inside.offsetWidth;
      }
      if (this.type === 'vertical') {
        wrapperOffset = wrapper.offsetHeight;
        insideOffset = inside.offsetHeight;
      }
      if (insideOffset > wrapperOffset) {
        this.createFakeDom(inside);
        this.timerId = window.setInterval(() => {
          this.run(insideOffset);
        }, this.interval);
      }
    },
    createFakeDom(inside) {
      const childNodes = inside.cloneNode(true).childNodes;
      const fakeDom = document.querySelector(`.${this.id}-fake`);
      for (let i = 0; i < childNodes.length; i++) {
        fakeDom.appendChild(childNodes[i]);
      }
      if (this.type === 'horizontal') {
        fakeDom.style.marginLeft = FAKE_DOM_INTERVAL + 'px';
      } else {
        fakeDom.style.marginTop = FAKE_DOM_INTERVAL + 'px';
      }
    },
    run(insideOffset) {
      this.distance -= this.speed;
      if (this.distance === -insideOffset - FAKE_DOM_INTERVAL)
        this.distance = insideOffset + FAKE_DOM_INTERVAL;
      this.fakeDistance -= this.speed;
      if (this.fakeDistance === -insideOffset * 2 - FAKE_DOM_INTERVAL)
        this.fakeDistance = FAKE_DOM_INTERVAL;
    }
  }
};
</script>
<style lang="scss" scoped>
.marquee-wrapper {
  width: 100%;
  height: 100%;
  overflow: hidden;

  .marquee-inside,
  .marquee-fake {
    display: inline-block;
  }
}
</style>
           

4.准备工作做好了,下面就是如何使用

注意:当高度(宽度)达不到时,是不能纵向(横向)滚动的。

(1)纵向使用

<div
      class="content">
      <MarqueeBox 
        :interval="70" 
        type="vertical">
        文字....
      </MarqueeBox>
    </div>
import MarqueeBox from './MarqueeBox.vue';
export default {
  name: 'xxx',
  components: { detailDialog, MarqueeBox },
};
.content {
  height: 50px;
}
           

(2)横向滚动

<div
      class="content">
      <MarqueeBox 
        :interval="70">
        文字....
      </MarqueeBox>
    </div>
import MarqueeBox from './MarqueeBox.vue';
export default {
  name: 'xxx',
  components: { detailDialog, MarqueeBox },
};
.content {
  white-space: nowrap; // 文字不换行
  width: 100px;
}
           

继续阅读