Vue 實現跑馬燈效果
前言
最近做活動需要做跑馬燈效果,其他同事也有實現,本來打算複製他們程式碼,發現都是使用setInterval
實現了,也沒有封裝為元件,所以自己用CSS3
實現了一下跑馬燈效果,並封裝為元件,這樣以後在需要寫的時候,只需要引入元件就可以了。
實現的效果如下
實現思路
HTML
結構父盒子固定,子盒子移動,幷包含需要效果的內容- 跑馬燈效果
CSS3
實現肯定需要infinite
(迴圈執行動畫) - 運動前需要計算父盒子的寬度(
wrapWidth
),還有子盒子的總寬度(offsetWidth
) - 需要給定速度通過寬度計算出
CSS3
動畫需要的時間duration
元件設計
向外暴露三個引數
- content: 因為滾動的資料大部分都是後臺獲取的,監聽 content,當 content 有值的時候開始滾動(content 可以是任何型別資料)
- delay: 多久時開始執行動畫只有第一次滾動時候生效(預設是 0.3s)
- speed: 速度(預設 100)
原始碼實現如下
原始碼中大部分都新增了註釋,如有問題請指出謝謝
<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 包
使用方法
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>
複製程式碼