vue 自动循环播放横向滚动公告

2,570 阅读1分钟

基于自身业务需求而开发的自动横向循环播放内容的组件 采用css 动画效果 可以自定义配置 每秒进步像素距离和首尾间距 展示

动画.gif

组件

<template>
  <div class="notice-bar" ref="noticeBarRef">
    <div class="notice-bar-content" ref="contentRef" :style="contentStyle">
      <slot></slot>
      <!-- 如果开启动画 内容循环 -->
      <template v-if="animateFlag">
        <span class="content-headway" :style="{ width: `${headway}px` }"></span>
        <slot></slot>
      </template>
    </div>
  </div>
</template>

<script>
export default {
  name: 'notice-bar',
  // 父组件传递数据
  props: {
    // 进步 每秒移动像素值
    speed: {
      type: Number,
      default: 50
    },
    // 首尾间距
    headway: {
      type: Number,
      default: 60
    }
  },
  data () {
    return {
      contentStyle: {
        transitionDuration: '0s',
        transform: 'translateX(0px)'
      },
      contentWidth: 0,
      time: 0,
      timer: undefined,
      animateFlag: false
    }
  },
  // 方法集合
  methods: {
    // 初始化
    init () {
      // 容器宽度
      const barWidth = this.$refs.noticeBarRef.offsetWidth
      // 内容宽度
      const contentWidth = this.$refs.contentRef.offsetWidth
      if (contentWidth >= barWidth) {
        // 内容宽度 + 间距
        this.contentWidth = contentWidth + this.headway
        this.animateFlag = true
        this.openCycle()
      }
    },
    // 开启循环
    openCycle () {
      // 内容宽度 / 进步数值 = 动画时长
      this.time = this.contentWidth / this.speed
      this.startAnimate()
      // 循环
      this.timer = setInterval(() => {
        this.startAnimate()
      }, this.time * 1000)
      // 消除定时器
      this.$once('hook:beforeDestroy', () => {
        clearInterval(this.timer)
        this.timer = null
      })
    },
    // 开启动画
    startAnimate () {
      // 动画初始状态
      this.contentStyle = {
        transitionDuration: '0s',
        transform: 'translateX(0px)'
      }
      // 动画开启 time 动画时间 contentWidth 动画长度
      setTimeout(() => {
        this.contentStyle = {
          transitionDuration: `${this.time}s`,
          transform: `translateX(-${this.contentWidth}px)`
        }
      }, 10)
    }
  },
  // 生命周期 - 页面完成(可以访问当前dom实例)
  mounted () {
    this.init()
  }
}
</script>

<style lang="scss" scoped>
.notice-bar {
  position: relative;
  display: flex;
  flex: 1;
  height: 100%;
  align-items: center;
  overflow: hidden;
  &::after {
    content: '';
    width: 30px;
    height: 100%;
    position: absolute;
    right: 0;
    background: linear-gradient(270deg, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%);
  }
  .notice-bar-content {
    position: absolute;
    white-space: nowrap;
    transition-timing-function: linear;
    .content-headway {
      display: inline-block;
    }
  }
}
</style>

组件引用

<template>
  <div class="stock-price-info">
    <notice-bar :width="info.width">
      <span>平安银行(000001)</span>
      <span>2022-08-31  14:52</span>
      <span>最新股价:15.52</span>
      <span>涨跌情况:-0.54/1.54%</span>
      <span>最高:17.45</span>
      <span>最低:16.33</span>
      <span>今开:16.88</span>
      <span>昨收:16.88</span>
      <span>换手率:15.23%</span>
      <span>成交量:25,245,234</span>
      <span>成交额:12.52亿元</span>
    </notice-bar>
  </div>
</template>

<script>
import NoticeBar from '@/components/contentBasics/NoticeBar'

export default {
  // import引入的组件需要注入到对象中才能使用
  components: { NoticeBar },
}
</script>

<style lang="scss" scoped>
.stock-price-info {
  padding: 0 16px;
  display: flex;
  align-items: center;
  background-color: #fff;
  border-radius: 3px;
}
</style>