效果如下图:(Vue走马灯的扩展版)
Vue走马灯_theMuseCatcher的博客-CSDN博客_vue滚动图片
可自定义设置
- 走马灯图片宽度
- 图片高度
- 滑动轮播时间间隔
- 轮播图片数组
主要具有以下功能:
- 根据设置的时间间隔自动定时滚动切换图片
- 鼠标移入组件内部时,暂停切换,移出后自动开始切换图片
- 页面未激活时会自动暂停切换,待激活时自动开始切换图片
- 鼠标移入组件内部时,点击左右箭头可以手动切换到上一张,下一张图片
- 根据传入图片数组展示相应数量的底部图片标识,并显示当前是第几张,同时点击可以直接切换到指定图片
该组件的所有滑动效果均采用的setInterval延时调用模拟,如果换成requestAnimationFrame()实现一样可行,具体实现可参考Vue简单走马灯_theMuseCatcher的博客-CSDN博客_vue滚动图片
①创建ImageSlider.vue组件:
<template>
<div class="m-slider" :style="`width: ${imageWidth}px;`" @mouseover="onStop" @mouseleave="onStart">
<div :class="{'transition': transition}" :style="`width: ${width}px; will-change: transform; transform: translateX(${-left}px);`">
<div
v-for="(item, index) in imageData"
:key="index"
:style="`width: ${imageWidth}px;`"
class="m-image">
<img v-lazy="getDefault(item && item.imgUrl)" :key="item && item.imgUrl" :alt="item && item.title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
<div class="m-title" :title="item && item.title">
<p class="u-title">{{ item && item.title || '--' }}</p>
<p class="u-date">2022/07/12</p>
</div>
</div>
<div class="m-image" :style="`width: ${imageWidth}px;`">
<img v-lazy="getDefault(imageData[0] && imageData[0].imgUrl)" :key="imageData[0] && imageData[0].imgUrl" :alt="imageData[0]&&imageData[0].title" :style="`width: ${imageWidth}px; height: ${imageHeight}px;`" class="u-img"/>
<div class="m-title" :title="imageData[0]&&imageData[0].title">
<p class="u-title">{{ imageData[0] && imageData[0].title || '--' }}</p>
<p class="u-date">2022/07/12</p>
</div>
</div>
</div>
<img src="@/assets/images/left-1.png" class="arrow-left" v-show="!leftActArrow" @mouseenter="leftActArrow=true" @mouseleave="leftActArrow=false" />
<img src="@/assets/images/left-2.png" class="arrow-left" @click="goRight((activeSwitcher+1)%len*imageWidth)" v-show="leftActArrow" @mouseenter="leftActArrow=true" @mouseleave="leftActArrow=false" />
<img src="@/assets/images/right-1.png" class="arrow-right" v-show="!rightActArrow" @mouseenter="rightActArrow=true" @mouseleave="rightActArrow=false"/>
<img src="@/assets/images/right-2.png" class="arrow-right" @click="goLeft(activeSwitcher%(len+1)*imageWidth)" v-show="rightActArrow" @mouseenter="rightActArrow=true" @mouseleave="rightActArrow=false"/>
<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>
import Vue from 'vue'
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad) // 图片懒加载插件
export default {
name: 'ImageSlider',
props: {
imageData: { // 轮播图片数组
type: Array,
default: () => {
return []
}
},
interval: { // 自动滑动轮播间隔
type: Number,
default: 3000
},
imageWidth: { // 图片宽度
type: Number,
default: 400
},
imageHeight: { // 图片高度
type: Number,
default: 300
}
},
data () {
return {
leftActArrow: false, // 左箭头激活标志
toLeft: true, // 左滑标志,默认左滑
rightActArrow: false, // 右箭头激活标志
left: 0, // 滑动偏移值
transition: false, // 暂停时为完成滑动的过渡标志
slideTimer: null, // 轮播切换定时器
moveTimer: null, // 向左滑动效果定时器
autoTimer: null, // 首次自动滑动定时器
switch: false // 是否在进行跳转切换,用于区别箭头或自动切换(false)和跳转切换(true)
}
},
computed: {
width () { // 容器宽度:(图片数组长度+1) * 图片宽度
return (this.imageData.length + 1) * this.imageWidth
},
len () { // 数组长度
return this.imageData.length || 0
},
activeSwitcher () { // 当前展示图片标志
return (this.toLeft ? Math.ceil(this.left / this.imageWidth) % this.len : Math.floor(this.left / this.imageWidth) % this.len) + 1
}
},
mounted () {
window.onfocus = () => { // 页面激活状态
this.onStart()
}
window.onblur = () => { // 页面未激活状态
this.onStop()
}
this.onStart()
},
methods: {
getDefault (src) { // 获取懒加载默认图
return {
src: src,
error: require('../assets/images/defaultNews.png'),
loading: require('../assets/images/defaultNews.png')
}
},
onSwitch (n) { // 切换图片
if (n < this.activeSwitcher) { // 往右滑动
this.switch = true // 跳转切换标志
const target = (n - 1) * this.imageWidth
this.goRight(target)
}
if (n > this.activeSwitcher) { // 往左滑动
this.switch = true // 跳转切换标志
const target = (n - 1) * this.imageWidth
this.goLeft(target)
}
},
onStart () {
if (this.len > 1) { // 超过一条时滑动
this.toLeft = true // 重置左滑标志
this.transition = false
this.onAutoSlide() // 自动滑动轮播
console.log('imageSlider start')
}
},
onStop () {
clearTimeout(this.autoTimer)
clearTimeout(this.slideTimer)
this.autoTimer = null
this.slideTimer = null
if (this.toLeft) { // 左滑箭头移出时
this.onStopLeft()
} else {
this.onStopRight()
}
console.log('imageSlider stop')
},
onStopLeft () { // 停止往左滑动
clearInterval(this.moveTimer)
this.moveTimer = null
this.transition = true
this.left = Math.ceil(this.left / this.imageWidth) * this.imageWidth // ceil:向上取整,floor:向下取整
},
onStopRight () { // 停止往右滑动
clearInterval(this.moveTimer)
this.moveTimer = null
this.transition = true
this.left = Math.floor(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)
},
goLeft (target) { // 点击右箭头,往左滑动
this.toLeft = true // 向左滑动
this.onStopLeft()
this.transition = false
this.moveLeft(target)
},
goRight (target) { // 点击左箭头,往右滑动
this.toLeft = false // 非向左滑动
this.onStopRight()
this.transition = false
this.moveRight(target)
},
autoMoveLeft (target) { // 自动切换,向左滑动效果
if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
this.left = 0
}
this.moveTimer = setInterval(() => {
if (this.left >= target) {
clearInterval(this.moveTimer)
this.moveTimer = null
this.onAutoSlide() // 自动间隔切换下一张
} else {
var step = Math.ceil((target - this.left) / 10) // 越来越慢的滑动过程
this.left += step
}
}, 25)
},
moveLeft (target) { // 箭头切换或跳转切换,向左滑动效果
if (this.left === this.len * this.imageWidth) { // 最后一张时,重置left
this.left = 0
}
this.moveTimer = setInterval(() => {
if (this.left >= target) {
clearInterval(this.moveTimer)
this.moveTimer = null
if (this.switch) { // 跳转切换,完成后自动滑动
this.switch = false
this.onStart()
}
} else {
var step = Math.ceil((target - this.left) / 10) // 越来越慢的滑动过程
this.left += step
}
}, 25)
},
moveRight (target) { // 箭头切换或跳转切换,向右滑动效果
if (this.left === 0) { // 第一张时,重置left
this.left = this.len * this.imageWidth
}
this.moveTimer = setInterval(() => {
if (this.left <= target) {
clearInterval(this.moveTimer)
this.moveTimer = null
if (this.switch) { // 跳转切换,完成后自动滑动
this.switch = false
this.onStart()
}
} else {
var step = Math.floor((target - this.left) / 10) // 越来越慢的滑动过程
this.left += step
}
}, 25)
},
beforeDestroy () {
clearTimeout(this.slideTimer)
clearInterval(this.moveTimer)
clearInterval(this.autoTimer)
this.slideTimer = null
this.moveTimer = null
this.autoTimer = null
}
}
}
</script>
<style lang="less" scoped>
@themeColor: #1890FF;
.m-slider {
position: relative;
overflow: hidden;
.transition {
transition: transform 0.3s ease-out;
}
.m-image {
display: inline-block;
.u-img {
vertical-align: bottom; // 消除img标签底部的5px
cursor: pointer;
}
.m-title {
background: #F2F4F8;
padding: 20px;
.u-title {
height: 54px;
font-size: 18px;
font-weight: 500;
color: #333333;
line-height: 27px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
&:hover {
color: @themeColor;
}
}
.u-date {
margin-top: 30px;
text-align: right;
height: 20px;
font-size: 14px;
font-weight: 400;
color: #666666;
line-height: 20px;
}
}
}
&:hover {
.arrow-left {
display: inline-block;
}
.arrow-right {
display: inline-block;
}
}
.arrow-left {
display: none;
width: 24px;
height: 44px;
position: absolute;
top: 151px;
left: 10px;
cursor: pointer;
vertical-align: bottom;
}
.arrow-right {
display: none;
width: 24px;
height: 44px;
position: absolute;
top: 151px;
right: 10px;
cursor: pointer;
vertical-align: bottom;
}
.m-switch {
position: absolute;
bottom: 16px;
left: 20px;
.u-rect {
display: inline-block;
cursor: pointer;
margin-right: 7px;
width: 30px;
height: 4px;
background: #E3E3E3;
border-radius: 1px;
transition: background-color 0.3s;
}
.active {
background: @themeColor;
}
}
}
</style>
②在要使用的页面引入:
<ImageSlider :imageData="imageData" :imageWidth="520" :imageHeight="346" :interval="3000" />
import ImageSlider from '@/components/ImageSlider'
components: {
ImageSlider
}
data () {
return {
imageData: [
{
title: 'image-1,image-1,image-1,image-1,image-1,image-1,image-1,image-1,image-1',
imgUrl: 'image src...'
},
{
title: 'image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2,image-2',
imgUrl: 'image src...'
},
{
title: 'image-3,image-3,image-3,image-3,image-3,image-3,image-3,image-3,image-3',
imgUrl: 'image src...'
}
]
}
}
|