欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue实现跑马灯效果

程序员文章站 2022-07-14 21:33:36
...

前言

目前项目中需要用到跑马灯效果,因此单独写了一个跑马灯组件。

 跑马灯需求效果描述:

1、在文字超过显示框的情况下,以跑马灯的形式显示全部

2、开始滚动前延迟1秒,从右向左滚动,滚动至初始位置为一轮

3、跑马灯滚动一轮后停顿片刻接着第二轮滚动

vue实现跑马灯效果

代码实现如下:

<template>
  <div class="hello">
    <h1>跑马灯</h1>
    <div class="test-content">
      <marquee-bar value="Jenny测试"></marquee-bar>
      <marquee-bar value="测试跑马灯的效果,在超出限定内容框时,是否能滚动起来"></marquee-bar>
      <marquee-bar value="内容滚动一轮后,停顿片刻继续滚动"></marquee-bar>
      <marquee-bar value="就这样吧"></marquee-bar>
    </div>
  </div>
</template>

<script>
import MarqueeBar from './MarqueeBar'
export default {
  name: 'HelloWorld',
  components: {
    MarqueeBar
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
.test-content {
  width: 200px;
  margin: 20px auto;
  padding: 5px;
  background-color: aquamarine;
}
</style>

 跑马灯组件代码:

<template>
  <div ref="wrap" class="wrap-content">
    <div
      ref="marqueeBar"
      class="marqueeBar"
      :class="animationClass"
      :style="marqueeBarStyle"
      @animationend="onAnimationEnd"
      @webkitAnimationEnd="onAnimationEnd"
    >{{value}}</div>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      default: ''
    },
    delay: {
      type: Number,
      default: 1
    },
    speed: {
      type: Number,
      default: 50
    }
  },
  mounted () {
    // 动态向头部插入样式表 主要是paomadeng-infinite中移动的值为动态的 根据手机屏幕宽度适配
    document.getElementById('keyframes_id') && document.getElementById('keyframes_id').remove()
    var style = document.createElement('style')
    style.type = 'text/css'
    style.id = 'keyframes_id'
    var keyFrames = `@keyframes paomadeng-infinite {
      to {
        transform: translate3d(-${this.$refs.wrap.getBoundingClientRect().width}px, 0, 0);
      }
    }`
    style.innerHTML = keyFrames
    document.getElementsByTagName('head')[0].appendChild(style)
  },
  data () {
    return {
      wrapWidth: 0, // 父盒子宽度
      firstRound: true, // 判断是否
      duration: 0, // css3一次动画需要的时间
      offsetWidth: 0, // 子盒子的宽度
      animationClass: '', // 添加animate动画
      loopNum: 0 // 循环次数
    }
  },
  computed: {
    marqueeBarStyle () {
      return {
        // 第一次从头开始,第二次动画的时候需要从最右边出来所以宽度需要多出父盒子的宽度
        paddingLeft: (this.firstRound ? 0 : this.wrapWidth) + 'px',
        // 只有第一次的时候需要延迟
        animationDelay: (this.firstRound ? this.delay : 0) + 's',
        animationDuration: this.duration + 's'
      }
    }
  },
  watch: {
    value: {
      // 监听到有内容,从后台获取到数据了,开始计算宽度,并计算时间,添加动画
      handler () {
        this.$nextTick(() => {
          const { wrap, marqueeBar } = this.$refs
          const wrapWidth = wrap.getBoundingClientRect().width
          const offsetWidth = marqueeBar.getBoundingClientRect().width
          if (offsetWidth > wrapWidth) {
            this.wrapWidth = wrapWidth
            this.offsetWidth = offsetWidth
            this.duration = offsetWidth / this.speed
            this.animationClass = 'animate'
          }
        })
      },
      immediate: true
    }
  },
  methods: {
    // 这个函数是第一次动画结束的时候,第一次没有使用infinite,第一次动画执行完成后开始使用添加animate-infinite动画
    onAnimationEnd () {
      this.loopNum = this.loopNum + 1
      this.firstRound = false
      if (this.loopNum == 1) {
        // 这是时候样式多出了padding-left:this.wrapWidth;所以要想速度一样需要重新计算时间
        this.duration = this.wrapWidth / this.speed
        this.animationClass = 'animate-infinite'
      } else if (this.loopNum == 2) {
        this.duration = this.offsetWidth / this.speed
        this.animationClass = 'animate'
        this.loopNum = 0
        this.firstRound = true
      }
    }
  }
}
</script>
<style scoped>
.wrap-content {
  width: 100%;
  height: 27px;
  overflow: hidden;
  position: relative;
  padding: 0;
}

.wrap-content .marqueeBar {
  position: absolute;
  white-space: nowrap;
}

.animate {
  animation: paomadeng linear forwards;
}

.animate-infinite {
  animation: paomadeng-infinite linear forwards;
}

@keyframes paomadeng {
  to {
    transform: translate3d(-100%, 0, 0);
  }
}

/* @keyframes paomadeng-infinite {
  to {
    transform: translate3d(-200px, 0, 0);
  }
} */
</style>

 项目git地址:https://github.com/lhz333/marqueeBar