先看效果图:

Vue 自定义轮播_轮播图

 开发可视化大屏的时候想在网上随便找一个,翻了翻都不太满意就手撸了一个,

配置信息如下:

Vue 自定义轮播_ico_02

有些属于“预留”功能,目前没有达到理想效果,后续我会在这篇博客里继续完善,

源码如下:

<template>
<div>
<div class="swiper-title">自定义轮播图</div>
<div class="swiper-box">
<!-- 轮播区域 -->
<div :class="[config.column ? 'column-row' : '']" class="swiper">
<div v-for="(item, index) in list" :key="index" :class="[nowInd === index ? 'focus' : '']" class="swiper-item"
:style="{
backgroundImage: `url(${item.url})`,
transition: `all ${nowFlag ? (config.changeTime < config.waitTime ? config.changeTime + 's' : '0.5s') : '0s'}`,
transform: config.column ? `translateX(-${100 * nowInd}%)` : `translateY(-${100 * nowInd}%)`,
}">
<p class="title">文字和图片没有什么关联</p>
<p class="info">图片是河南开封的美景</p>
<p class="name">{{ item.name }}</p>
</div>
</div>
<!-- 指示点 -->
<div v-if="config.spot" class="spot-flex">
<div @click="spotActive(ind)" v-for="ind in list.length - 1" :key="ind"
:class="[nowInd === ind ? 'focus' : '', config.spotStyle ? `spot${config.spotStyle}` : 'spot1']" class="spot">
</div>
</div>
<!-- 左右切换 -->
<img v-if="config.arrow" @click="spotActive('-')"
src="https://img-blog.csdnimg.cn/ae2239969edd48cc803da677dd791865.png" alt="" class="icon left">
<img v-if="config.arrow" @click="spotActive('+')"
src="https://img-blog.csdnimg.cn/46d9862a4c3e42819a79ebd2b84d0d73.png" alt="" class="icon right">
<!-- 控制台 -->
<!-- <div class="operate">
<div class="row">
<span>排列方式:</span>
<input type="radio">
<input type="radio">
<input v-model="config.column" type="text">
</div>
</div> -->
</div>
</div>
</template>
<script>
export default {
name: "Swiper",
data() {
return {
config: {
column: true, // true: 横向排列 false: 纵向排列
changeStyle: 2, // 切换风格 (可选1、2)
changeTime: 1, // 转换时长(秒) 转换时长必须小于等待时长,默认为500毫秒
waitTime: 2, // 等待时长(秒) 等待时长最短为1s
spot: true, // 指示点 true: 显示 false: 隐藏
spotStyle: 1, // 指示点风格 (可选1、2、3)
arrow: false, // 左右切换按钮 true: 显示 false: 隐藏
},
nowInd: 0, // 轮播图当前下标
nowFlag: true, // 过渡控制器
myInt: '', // 轮播图计时器
list: [
{ name: '巍峨壮丽连绵不绝的山脉', url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimagepphcloud.thepaper.cn%2Fpph%2Fimage%2F206%2F104%2F959.jpg&refer=http%3A%2F%2Fimagepphcloud.thepaper.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147037&t=19521f70b52350b3d1ad05c57d71dd0e' },
{ name: '傍晚的天空和海面的霞光', url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.dazijia.com%2FUploads%2Fjingdian%2F20210323%2Fy605991b3e31d3.jpg&refer=http%3A%2F%2Fwww.dazijia.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147229&t=f32746ac1f21b8e1d243747e9353fa16https://img0.baidu.com/it/u=2725915437,1236608227&fm=253&fmt=auto&app=138&f=JPEG?w=750&h=500' },
{ name: '峻峭的雪山景色', url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fphoto.tuchong.com%2F1658968%2Ff%2F149475915.jpg&refer=http%3A%2F%2Fphoto.tuchong.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663147301&t=1be195b9d22a1307a66fb8e19697fb54' }
]
}
},
mounted() {
this.list.length > 0 ? this.list.push(this.list[0]) : '';
this.autoInt()
},
methods: {
// 轮播图计时器
autoInt() {
clearInterval(this.myInt)
this.myInt = setInterval(() => {
this.nowInd++
if (this.nowInd > this.list.length - 1) {
this.nowFlag = false;
this.nowInd = 0
setTimeout(() => {
this.nowFlag = true;
this.nowInd++
}, 10)
}
}, this.config.waitTime * 1000 < 1000 ? 1000 : this.config.waitTime * 1000)
},
// 指示点/左右按钮点击
spotActive(ind) {
if (ind === '+') {
this.nowInd < this.list.length - 2 ? this.nowInd++ : this.nowInd = 0
} else if (ind === '-') {
this.nowInd > 0 ? this.nowInd-- : this.nowInd = this.list.length - 2
} else {
this.nowInd = ind;
}
this.autoInt()
},
}
}
</script>
<style lang="scss" scoped>
.swiper-title {
width: 600px;
text-align: center;
line-height: 40px;
font-size: 22px;
font-family: 仿宋;
font-weight: 500;
color: #f7c40b;
}

.column-row {
white-space: nowrap;

.swiper-item {
display: inline-block;
}
}

.swiper-box {
position: relative;
width: 600px;
height: 360px;

.swiper {
width: 100%;
height: 100%;
overflow: hidden;

.swiper-item {
width: 100%;
height: 100%;
background: no-repeat center;
background-size: cover;
overflow: hidden;

.title,
.info,
.name {
transform: translateX(-100%)
}
}

.focus {

.title,
.info,
.name {
transform: translateX(20px);
}

.title {
transition: all .6s .3s;
}

.info {
transition: all .6s .5s;
}

.name {
transition: all .6s .7s;
}
}
}

.icon {
position: absolute;
top: 0;
bottom: 0;
margin: auto;
width: 30px;
height: 30px;
border-radius: 50%;
cursor: pointer;
}

.left {
left: 0;
}

.right {
right: 0;
}

.spot-flex {
position: absolute;
left: 0;
right: 0;
bottom: -20px;
margin: auto;
display: flex;
justify-content: center;
align-items: center;

.spot1 {
width: 30px;
height: 8px;
margin: 0 10px;
border-radius: 4px;
background-color: pink;
transition: all .6s;
cursor: pointer;
}

.spot2 {
width: 6px;
height: 6px;
margin: 0 10px;
border: 2px solid #acd6f3;
transform: rotate(45deg);
transition: all .6s;
cursor: pointer;
}

.spot3 {
width: 6px;
height: 6px;
margin: 0 10px;
border-radius: 3px;
box-shadow: 0px 0px 6px 3px #acd6f3;
transition: all .6s;
cursor: pointer;
}

.focus {
background-color: skyblue;
}
}
}

.operate {
margin-left: 40px;

.row {
display: flex;
align-items: center;
font-size: 14px;
}
}
</style>

组件开发的比较潦草,后续会进行迭代和完善,继续在这篇文章里进行更新。

设计思路如下:

Vue 自定义轮播_轮播图_03

划分标题、轮播区、指示点三块,在轮播区使用 display: inline-block; 使子元素横向排列,

Vue 自定义轮播_复用_04

此时限制父元素的宽度,子元素会自动换行,使用 white-space: nowrap; 则强制不换行。

使用动态样式的写法,判断column

Vue 自定义轮播_复用_05

Vue 自定义轮播_轮播图_06

Vue 自定义轮播_轮播图_07

使用计时器控制变量 nowInd 变化,当nowInd

Vue 自定义轮播_ico_08

根据config.column 的值,判断是进行左右移动 还是上下移动,用transition

Vue 自定义轮播_1024程序员节_09

文字的滑动效果来自于 css 动画,代码如下:

.focus {
.title,.info,.name {
transform: translateX(20px);
}

.title {
transition: all .6s .3s;
}

.info {
transition: all .6s .5s;
}

.name {
transition: all .6s .7s;
}
}

Vue 自定义轮播_轮播图_10

通过nowInd 是否等于当前子元素的下标,以此来断定是否聚焦了当前的子元素,当子元素满足条件拥有.focus

Vue 自定义轮播_1024程序员节_11

Vue 自定义轮播_轮播图_12

Vue 自定义轮播_轮播图_13

三种指示点共用同一套动画,样式也进行和封装和复用,需要别的款式可以仿照我现在的代码进行更改。

Vue 自定义轮播_轮播图_14

这里为了高度复用性,使用的并不是img 轮播,而是div 区域轮播,以背景图的形式体现

Vue 自定义轮播_1024程序员节_15

可以根据不同的需求更改或隐藏背景图,在div 里进行自定义排版。

暂时就讲到这里了,后续会在这篇文章的底部继续更新该组件,感兴趣的话可以收藏一下,see you