效果如下图:
可自定义设置:
- 滑动轮播间隔
- 整体图片区域宽度
①创建多图组合走马灯组件MultiImageSlider.vue:
<template>
<div class="m-slider">
<div
@mouseenter="onStop"
@mouseleave="onStart"
:class="{'transition': transition}"
:style="`width: ${width}px; will-change: transform; transform: translateX(${-left}px);`">
<div
v-for="(logos, index) in multiImageData"
:key="index"
:style="`width: ${imageWidth}px;`"
class="m-image">
<a
v-for="(item, ind) in logos"
:key="ind"
:href="item.ur"
:class="['m-logo',{ 'mt18': ind > 5 }]"
target="_blank">
<a class="u-logo" v-lazy:background-image="getDefault(item.logo)" :key="item.logo"></a>
</a>
</div>
<div class="m-image" :style="`width: ${imageWidth}px;`">
<a
v-for="(first, index) in multiImageData[0]"
:key="index"
:href="first.url"
:class="['m-logo',{ 'mt18': index > 5 }]"
target="_blank">
<a class="u-logo" v-lazy:background-image="getDefault(first.logo)" :key="first.logo"></a>
</a>
</div>
</div>
<div class="m-switch">
<div
@click="onSwitch(n)"
:class="['u-rect', {'active': activeSwitcher === n }]"
v-for="n in len"
:key="n">
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MultiImageSlider',
props: {
multiImageData: { // 图片数据,必传
type: Array,
required: true,
default: () => {
return [[]]
}
},
interval: { // 滑动轮播间隔
type: Number,
default: 3000
},
imageWidth: { // 整体图片区域宽度
type: Number,
default: 1200
}
},
data () {
return {
toLeft: true, // 左滑标志,默认左滑
left: 0, // 偏移值
transition: false, // 悬浮时的transition时间
slideTimer: null, // 轮播定时器
moveRaf: null, // 动画回调标识
target: null, // 要移动到的目标位置
start: 0,
end: 0,
fpsRaf: null, // fps回调标识
step: 30 // 默认移动参数,对应60fps
}
},
computed: {
width () { // 容器宽度:(图片数组长度+1) * 图片宽度
return (this.multiImageData.length + 1) * this.imageWidth
},
len () {
return this.multiImageData.length || 0
},
activeSwitcher () { // 当前展示图片标志
return (this.toLeft ? Math.ceil(this.left / this.imageWidth) % this.len : Math.floor(this.left / this.imageWidth) % this.len) + 1
}
},
mounted () {
this.fpsRaf = requestAnimationFrame(this.getFPS) // 获取浏览器的刷新率
},
methods: {
getDefault (src) {
return {
src: src,
error: require('../assets/images/defaultLogo.png'),
loading: require('../assets/images/defaultLogo.png')
}
},
getFPS (timestamp) {
// 单位ms,用1000ms/两个时间的间隔≈刷新频率fps
// console.log('timestamp:', timestamp)
if (this.fpsRaf === 2) {
this.start = timestamp
}
if (this.fpsRaf === 3) {
this.end = timestamp
const fps = Math.floor(1000 / (this.end - this.start))
if (fps === 120) {
this.step = 15
}
}
this.fpsRaf = requestAnimationFrame(this.getFPS)
if (this.fpsRaf > 3) {
cancelAnimationFrame(this.fpsRaf)
this.onStart()
}
},
onSwitch (n) { // 切换图片
clearTimeout(this.slideTimer)
if (n < this.activeSwitcher) { // 往右滑动
const target = (n - 1) * this.imageWidth
this.goRight(target)
}
if (n > this.activeSwitcher) { // 往左滑动
const target = (n - 1) * this.imageWidth
this.goLeft(target)
}
},
onStart () {
if (this.len > 1) {
this.toLeft = true // 重置左滑标志
this.transition = false
this.onAutoSlide() // 自动滑动轮播
console.log('organSlider start')
}
},
onStop () {
clearTimeout(this.slideTimer)
this.slideTimer = null
if (this.toLeft) { // 往左滑动时
this.onStopLeft()
} else {
this.onStopRight()
}
console.log('organSlider stop')
},
goRight (target) { // 往右滑动
this.toLeft = false // 非向左滑动
this.onStopRight()
this.transition = false
this.moveRight(target)
},
onStopRight () { // 停止往右滑动
cancelAnimationFrame(this.moveRaf)
this.transition = true
this.left = Math.floor(this.left / this.imageWidth) * this.imageWidth // ceil:向上取整,floor:向下取整
},
goLeft (target) { // 往左滑动
this.toLeft = true // 向左滑动
this.onStopLeft()
this.transition = false
this.moveLeft(target)
},
onStopLeft () { // 停止往左滑动
cancelAnimationFrame(this.moveRaf)
this.transition = true
this.left = Math.ceil(this.left / this.imageWidth) * this.imageWidth // ceil:向上取整,floor:向下取整
},
onAutoSlide () { // 自动左滑切换
this.slideTimer = setTimeout(() => {
// 或者使用 this.activeSwitcher % (this.len + 1) * this.imageWidth
const target = this.left % (this.len * this.imageWidth) + this.imageWidth
this.autoMoveLeft(target)
}, this.interval)
},
autoMoveLeft (target) {
if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
this.left = 0
}
this.target = target
this.moveRaf = requestAnimationFrame(this.autoLeftSlideEffect)
},
autoLeftSlideEffect () { // 自动向左滑动效果
if (this.left >= this.target) {
cancelAnimationFrame(this.moveRaf)
this.onAutoSlide() // 自动间隔切换下一张
} else {
this.left += this.step
this.moveRaf = requestAnimationFrame(this.autoLeftSlideEffect)
}
},
moveRight (target) {
if (this.left === 0) { // 第一张时,重置left
this.left = this.len * this.imageWidth
}
this.target = target
this.moveRaf = requestAnimationFrame(this.rightSlideEffect)
},
rightSlideEffect () { // 向右滑动效果
if (this.left <= this.target) {
cancelAnimationFrame(this.moveRaf)
this.onStart() // 跳转切换完成,自动切换
} else {
this.left -= this.step
this.moveRaf = requestAnimationFrame(this.rightSlideEffect)
}
},
moveLeft (target) {
if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
this.left = 0
}
this.target = target
this.moveRaf = requestAnimationFrame(this.leftSlideEffect)
},
leftSlideEffect () { // 向左滑动效果
if (this.left >= this.target) {
cancelAnimationFrame(this.moveRaf)
this.onStart() // 跳转切换完成,自动切换
} else {
this.left += this.step
this.moveRaf = requestAnimationFrame(this.leftSlideEffect)
}
},
beforeDestroy () {
clearTimeout(this.slideTimer)
this.slideTimer = null
}
}
}
</script>
<style lang="less" scoped>
@themeColor: #FBBF00;
.m-slider {
position: relative;
overflow: hidden;
height: 230px;
width: 1200px;
margin: 0 auto;
.transition {
transition: transform 0.5s ease-out;
}
.m-image {
display: inline-block;
vertical-align: top;
.mt18 {
margin-top: 18px;
}
.m-logo {
display: inline-block;
width: 183px;
height: 72px;
background: #FFFFFF;
border: 1px solid #E4E5E8;
cursor: pointer;
&:not(:nth-child(6n)) {
margin-right: 18px;
}
.u-logo {
display: inline-block;
width: 153px;
height: 42px;
margin: 15px;
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
}
}
.m-switch {
width: 1200px;
margin: 0 auto;
text-align: center;
position: absolute;
bottom: 0px;
line-height: 4px;
.u-rect {
display: inline-block;
cursor: pointer;
width: 30px;
height: 4px;
background: #E3E3E3;
border-radius: 1px;
transition: background-color 0.5s;
vertical-align: top;
&:not(:last-child) {
margin-right: 7px;
}
}
.active {
background: @themeColor;
}
}
}
</style>
②在要使用的页面引入:
<MultiImageSlider v-if="organData.length" :multiImageData="organData" :imageWidth="1200" :interval="5000" style="margin-top: 60px;" />
import MultiImageSlider from '@/components/MultiImageSlider'
components: {
MultiImageSlider
}
var organs = [...res.lists]
const page = Math.ceil(res.count / 12) // 一共多少页
for (var i = 0; i < page; i++) {
this.organData.push(organs.splice(0, 12))
}