Vue實現跑馬燈效果以及封裝爲組件發佈

Vue 實現跑馬燈效果

前言

最近作活動須要作跑馬燈效果,其餘同事也有實現,原本打算複製他們代碼,發現都是使用setInterval實現了,也沒有封裝爲組件,因此本身用CSS3實現了一下跑馬燈效果,並封裝爲組件,這樣之後在須要寫的時候,只須要引入組件就能夠了。css

實現的效果以下

實現思路

  • HTML 結構父盒子固定,子盒子移動,幷包含須要效果的內容
  • 跑馬燈效果 CSS3 實現確定須要 infinite (循環執行動畫)
  • 運動前須要計算父盒子的寬度(wrapWidth),還有子盒子的總寬度(offsetWidth)
  • 須要給定速度經過寬度計算出CSS3動畫須要的時間duration

組件設計

向外暴露三個參數vue

  • content: 由於滾動的數據大部分都是後臺獲取的,監聽 content,當 content 有值的時候開始滾動(content 能夠是任何類型數據)
  • delay: 多久時開始執行動畫只有第一次滾動時候生效(默認是 0.3s)
  • speed: 速度(默認 100)

github 地址源碼地址css3

源碼實現以下

源碼中大部分都添加了註釋,若有問題請指出謝謝git

<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;
      //這是時候樣式多出了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>
複製代碼

把源碼發佈到 npm 上

請參考個人另一篇文章,如何將本身的 vue 組件發佈爲 npm 包github

使用方法

github 如何使用地址和源碼地址web

npm install heyushuo-marquee --save
import PaoMaDeng from 'heyushuo-marquee';
<PaoMaDeng :delay="0.5" :speed="100" :content="arr"> <span v-for="(item, index) in arr" :key="index">{{item}}</span> </PaoMaDeng>
複製代碼

github 如何使用地址和源碼地址npm

相關文章
相關標籤/搜索