需求背景:例如大屏需要显示一周的排班信息、菜单信息、亦或者轮播展示某个部门的员工信息,这时候需要进行跑马灯似的无缝滚动效果
实现方式一
-
使用css动画结合关键帧进行实现
-
animation的常见属性
- animation-name 动画名称
- animation-duration 规定动画完成一个周期所花费的秒或毫秒
- animation-iteration-count 规定动画被播放的次数
- 可以是整数或者小数
- infinite 无限
- animation-timing-function 规定动画的速度曲线
- ease(默认)动画以低速开始,然后加快,在结束前变慢,速度类似正态分布曲线
- linear 匀速运动
- ease-in 低速开始、
- ease-out 低速结束
- ease-in-out 动画以低速开始和结束
- steps 指定了时间函数中的间隔数量(步长)(动画分几步完成)
- animation-play-state 规定动画是否正在运行或暂停。默认是" running" 还有’ paused 暂停
- 可以制作当鼠标移除轮播区域是进行动画暂停,提高用户体验
-
可以进行简写(推荐)
- animation: ygmove 10s infinite linear;
@keyframes ygmove {
to {
transform: translateX(-1700px); // 规定ygmove动画是在x轴负方向移动1700px的距离
}
}
- 代码
<template>
<div>
<div class="yg-list flex">
<div class="yg-content">
<div class="yg-content-move flex">
<div
class="yg-item flex"
v-for="(ygItem, ygIndex) in ygData"
:key="ygIndex"
>
<div class="yg-info flex">
<div class="yg-img">
<img :src="ygItem.headImg" alt="">
</div>
<div class="yg-name">{{ ygItem.name }}</div>
<div class="yg-gangwei">{{ ygItem.yggangweiEnumValue }}</div>
</div>
<div class="yg-zheng-pic">
<img :src="ygItem.zhengshiUrl" alt="">
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
ygData: [
{
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx2.sinaimg.cn/mw690/005Dg9pggy1hqv02dv5pkj32vo2vokc6.jpg',
name: '动作1',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作2',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx4.sinaimg.cn/mw690/005Dg9pggy1hqv02i51fej33pc3pce81.jpg',
name: '动作3',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作4',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx4.sinaimg.cn/mw690/005Dg9pggy1hqv02i51fej33pc3pce81.jpg',
name: '动作5',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx2.sinaimg.cn/mw690/005Dg9pggy1hqv02dv5pkj32vo2vokc6.jpg',
name: '动作1',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作2',
yggangweiEnumValue: '保姆'
}
]
}
},
methods: {}
}
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 0 !important;
}
::-webkit-scrollbar {
width: 0 !important;
height: 0;
}
.flex {
display: flex;
}
.yg-list {
padding: 15px;
width: 712px;
height: 180px;
background: linear-gradient(0deg, rgba(0, 115, 255, 0.59) 0%, rgba(0, 140, 255, 0) 100%);
border: 1px solid #5FB2FF;
overflow-x: scroll;
white-space: nowrap;
.yg-content {
width: 1000px;
height: 150px;
overflow: hidden;
.yg-content-move {
// ygmove 动画名
// 10s 动画完成一个周期所花费的秒或毫秒
// infinite 动画被播放的次数
// linear 规定动画的速度曲线
animation: ygmove 10s infinite linear;
}
}
.yg-item {
flex-shrink: 0;
padding: 12px;
margin-right: 20px;
width: 320px;
height: 148px;
border: 1px solid rgba(0, 229, 255, 0.5);
.yg-info {
justify-content: space-between;
flex-direction: column;
align-items: center;
margin-right: 15px;
width: 78px;
height: 124px;
font-size: 14px;
color: #fff;
.yg-img {
width: 78px;
height: 78px;
border-radius: 4px;
box-shadow: 0px 0px 5px 0px #00E5FF;
overflow: hidden;
}
}
.yg-zheng-pic {
width: 203px;
height: 124px;
border-radius: 4px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
}
}
@keyframes ygmove {
to {
transform: translateX(-1700px);
}
}
</style>
实现方式二
- 使用vue-seamless-scroll(推荐)
- 步骤
- 下包
--> npm
npm install vue-seamless-scroll --save
--> yarn
yarn add vue-seamless-scroll
--> cdn
https://cdn.jsdelivr.net/npm/vue-seamless-scroll@latest/dist/vue-seamless-scroll.min.js
- 引入组件
// main.js
// 在main.js中引入 作为全局
import seamlessScroll from 'vue-seamless-scroll'
Vue.use(seamlessScroll)
- 使用
<template>
<div>
<!-- 消息滚动组件,区域多大它滚动的地方就有多大 -->
<!-- <test-scroll></test-scroll> -->
<div class="yg-list flex">
<div class="yg-content">
<vue-seamless-scroll :data="ygData" class="yg-content" :class-option="defaultOption">
<div class="yg-content-move flex">
<div
class="yg-item flex"
v-for="(ygItem, ygIndex) in ygData"
:key="ygIndex"
>
<div class="yg-info flex">
<div class="yg-img">
<img :src="ygItem.headImg" alt="">
</div>
<div class="yg-name">{{ ygItem.name }}</div>
<div class="yg-gangwei">{{ ygItem.yggangweiEnumValue }}</div>
</div>
<div class="yg-zheng-pic">
<img :src="ygItem.zhengshiUrl" alt="">
</div>
</div>
</div>
</vue-seamless-scroll>
</div>
</div>
</div>
</template>
<script>
// import TestScroll from './components/TestScroll.vue'
export default {
// components: { TestScroll },
data() {
return {
ygData: [
{
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx2.sinaimg.cn/mw690/005Dg9pggy1hqv02dv5pkj32vo2vokc6.jpg',
name: '动作1',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作2',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx4.sinaimg.cn/mw690/005Dg9pggy1hqv02i51fej33pc3pce81.jpg',
name: '动作3',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作4',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx4.sinaimg.cn/mw690/005Dg9pggy1hqv02i51fej33pc3pce81.jpg',
name: '动作5',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://wx2.sinaimg.cn/mw690/005Dg9pggy1hqv02dv5pkj32vo2vokc6.jpg',
name: '动作1',
yggangweiEnumValue: '保姆'
}, {
headImg: require('../src/assets/zheng-em-man.png'),
zhengshiUrl: 'https://ww2.sinaimg.cn/mw690/005Dg9pggy1hqv02lw9elj33pc3pcb29.jpg',
name: '动作2',
yggangweiEnumValue: '保姆'
}
],
}
},
computed: {
// defaultOption 可以写在data中的,但是需要获取滚动数量,因此写在computed中
defaultOption () {
return {
step: 10, // 数值越大速度滚动越快
limitMoveNum: this.ygData.length, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 2, // 0向下 1向上 2向左 3向右
openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000, // 单步运动停止的时间(默认值1000ms)
delay: 0
}
}
}
}
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
/* 內减模式 */
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 0 !important;
}
::-webkit-scrollbar {
width: 0 !important;
height: 0;
}
.flex {
display: flex;
}
.yg-list {
padding: 15px;
width: 712px;
height: 180px;
background: linear-gradient(0deg, rgba(0, 115, 255, 0.59) 0%, rgba(0, 140, 255, 0) 100%);
border: 1px solid #5FB2FF;
overflow-x: scroll;
white-space: nowrap;
.yg-content {
width: 1000px;
height: 150px;
overflow: hidden;
.yg-content-move {
// animation: ygmove 5s infinite ease-in;
}
}
.yg-item {
flex-shrink: 0;
padding: 12px;
margin-right: 20px;
width: 320px;
height: 148px;
// background-color: orange;
border: 1px solid rgba(0, 229, 255, 0.5);
.yg-info {
justify-content: space-between;
flex-direction: column;
align-items: center;
margin-right: 15px;
width: 78px;
height: 124px;
font-size: 14px;
color: #fff;
.yg-img {
width: 78px;
height: 78px;
border-radius: 4px;
box-shadow: 0px 0px 5px 0px #00E5FF;
overflow: hidden;
}
}
.yg-zheng-pic {
width: 203px;
height: 124px;
border-radius: 4px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
}
}
// @keyframes ygmove {
// to {
// transform: translateX(-1700px);
// }
// }
// .yg-content:hover .yg-content-move {
// animation-play-state: paused;
// }
</style>
两者的比较
通过css的方式不太灵活,第一种方法适用于轮播数量已知的情况下,存在以下问题
- 它需要根据滚动窗口大小对滚动数据追加相应的前几条数据方便实现无缝效果,例如滚动窗口可以看到两个滚动卡片,一共五个卡片,当五个卡片滚动完一次后会出现滚动窗口留白的情况,因为滚动窗口可以看到两个卡片,需要将前两个卡片数据追加到数据末尾来填充留白问题
- 而且在数据不确定的情况下,动画时间也需要进行相应设置例如数据有五条,动画设置5s完成就行,当数据变成10条时,动画完成时间还是5s,造成速度是之前的二倍
尽管可以根据数据量不同来操作dom设置这些数据,但还是相对麻烦的,而相比来说第二种方式可以动态设置数据量以及速度,避免了之前的问题