vue自定义走马灯,类似弹幕

效果:
在这里插入图片描述
公共组件

// Race.vue
<template>
  <div ref="wrap" class="wrap">
    <div ref="content" class="content" :class="animationClass" :style="contentStyle" @animationend="onAnimationEnd"
      @webkitAnimationEnd="onAnimationEnd">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    content: {
      default: ''
    },
    delay: {
      type: Number,
      default: 0.5
    },
    speed: {
      type: Number,
      default: 100
    }
  },
  mounted () { },
  data () {
    return {
      wrapWidth: 0,
      // 父盒子宽度
      firstRound: true,
      // 判断是否
      duration: 0,
      // css3一次动画需要的时间
      offsetWidth: 0,
      // 子盒子的宽度
      animationClass: ''
      // 添加animate动画
    }
  },
  computed: {
    contentStyle () {
      return {
        // 第一次从头开始,第二次动画的时候需要从最右边出来所以宽度需要多出父盒子的宽度
        paddingLeft: (this.firstRound ? 0 : this.wrapWidth) + 'px',
        // 只有第一次的时候需要延迟
        animationDelay: (this.firstRound ? this.delay : 0) + 's',
        animationDuration: this.duration + 's'
      }
    }
  },
  watch: {
    content: {
      // 监听到有内容,从后台获取到数据了,开始计算宽度,并计算时间,添加动画
      handler () {
        this.$nextTick(() => {
          const { wrap, content } = this.$refs
          const wrapWidth = wrap.getBoundingClientRect().width
          const offsetWidth = content.getBoundingClientRect().width
          this.wrapWidth = wrapWidth
          this.offsetWidth = offsetWidth
          this.duration = offsetWidth / this.speed
          this.animationClass = 'animate'
        })
      }
    }
  },
  methods: {
    // 这个函数是第一次动画结束的时候,第一次没有使用infinite,第一次动画执行完成后开始使用添加animate-infinite动画
    onAnimationEnd () {
      this.firstRound = false
      this.$refs.content.style.opacity = 0
      setTimeout(() => {
        this.$refs.content.style.opacity = 1
      }, 20)
      // 这是时候样式多出了padding-left:this.wrapWidth;所以要想速度一样需要重新计算时间
      this.duration = (this.offsetWidth + this.wrapWidth) / this.speed
      this.animationClass = 'animate-infinite'
    }
  }
}
</script>
<style scoped>
.wrap {
  width: 100%;
  height: 24px;
  overflow: hidden;
  position: relative;
  background: rgba(211, 125, 066, 1);
  position: relative;
  padding: 0;
}

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

.animate {
  animation: paomadeng linear;
}

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

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

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

使用

    <div style="width:300px;margin:0 auto">
      <Race :delay="0.5" :speed="100" :content="listC">
        <span v-for="(item, index) in listA" :key="index" style="marginRight:10px">
          <img :src="item.img" alt="" style="width:20px;height:20px;borderRadius:50%">
          <span style="color:green">{{item.name}}</span>{{item.text}}
        </span>
      </Race>
      <Race :delay="0.9" :speed="100" :content="listC">
        <span v-for="(item, index) in listB" :key="index" style="marginRight:10px">
          <img :src="item.img" alt="" style="width:20px;height:20px;borderRadius:50%">
          <span style="color:green">{{item.name}}</span>{{item.text}}
        </span>
      </Race>
    </div>
import Race from '@/components/Race'
components: { Race },
data () {
  return {
    lists: []
  }
},
mounted () {
  this.lists = [
      { text: '连雨不知春去', name: '张三', img: 'https://pic2.zhimg.com/80/v2-8df0e1ada7af09d3c62f2ba5ec4e4266_hd.jpg' },
      { text: '一晴方觉夏深', name: '李四', img: 'https://pic2.zhimg.com/80/v2-8df0e1ada7af09d3c62f2ba5ec4e4266_hd.jpg' },
      { text: '连雨不知春去', name: '张三', img: 'https://pic2.zhimg.com/80/v2-8df0e1ada7af09d3c62f2ba5ec4e4266_hd.jpg' },
      { text: '一晴方觉夏深', name: '李四', img: 'https://pic2.zhimg.com/80/v2-8df0e1ada7af09d3c62f2ba5ec4e4266_hd.jpg' }
    ]
},
computed () {
  listA () {
      return this.lists.slice(0, Math.floor(this.lists.length / 2))
    },
    listB () {
      return this.lists.slice(Math.floor(this.lists.length / 2), this.lists.length)
    },
    listC () {
      console.log(this.lists.map(item => {
        return item.name + item.name + item.text
      }))
      return this.lists.map(item => {
        return item.name + item.name + item.text
      })
    }
}

本文参考自Vue版跑马灯效果,Vue无缝滚动效果


文章作者: qiangqiang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 qiangqiang !
评论
 上一篇
vue实现自定义步骤条 vue实现自定义步骤条
首先看一下实现的效果: 来看看实现过程: 公共插件 <!-- Step.vue --> <template> <div class="stepOut"> <
2019-11-19
下一篇 
vue支付密码插件实现(可解决浏览器记住密码行为) vue支付密码插件实现(可解决浏览器记住密码行为)
浏览器自动填充和记住密码行为是前端遇到最为头疼的问题之一,浏览器只要检查到password input框,就会匹配离他最近的text input框,autocomplete属性虽能解决自动填充的问题,但是也是支持有限,不能解决浏览器记住密
2019-11-11
  目录