2020-02-15
很喜欢bilibili上的轮播图造型,这次就来自己写一下B站上的轮播图吧。
首先,B站分旧版和新版,仔细观察会发现,轮播图用的明显不是一套代码,因为旧版轮播图,播到最后一张时就倒回去了,是的,因为每一张图都有过渡,必须遵循这个规则,而且不可能第一张跑在最后一张的后面,这样用户体验不是很好,但我们还是要来做一下这种轮播图。
本次采用Vue框架进行开发,当然原生js和JQuery也可以,但是Vue支持数据双向绑定,响应速度快,简单,更便于维护。
旧版轮播图
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
a{
text-decoration: none;
}
li{
list-style-type: none;
}
.carousel {
max-width: 440px;
height: 220px;
position: relative;
overflow: hidden;
border-radius: 4px;
float: left;
}
.carousel .pic {
height: 220px;
transition: 1s ease;
}
.carousel img {
width: 440px;
height: 220px;
}
.carousel .pic li {
float: left;
}
/* 标题过渡 */
.carousel .title li {
position: absolute;
bottom: 10px;
left: 10px;
transition: .5s;
}
.carousel .title a {
color: white;
}
.carousel .trig {
position: absolute;
right: 35px;
bottom: 10px;
}
.carousel .trig li {
float: left;
background-image: url(img/icons.png);
background-position: -855px -790px;
width: 18px;
height: 18px;
margin-left: 5px;
cursor: pointer;
}
.carousel .trig li:hover {
background-position: -919px -790px;
}
.on {
background-position: -855px -727px !important;
width: 18px;
height: 18px;
}
.show {
opacity: 1;
}
.hide {
opacity: 0;
}
</style>
</head>
<body>
<div class="carousel" @mouseover="mouseover" @mouseout="mouseout">
<ul class="pic" :style="style">
<li v-for="(item,index) in pics"><a :href="pics[index].url"><img :src="pics[index].src"></a></li>
</ul>
<ul class="title">
<li v-for="(item,index) in pics" :class="pics[index].on?'show':'hide'"><a :href="pics[index].url">{{pics[index].title}}</a></li>
</ul>
<ul class="trig">
<li v-for="(item,index) in pics" :class="{on:pics[index].on}" @click="toggle(index)"></li>
</ul>
</div>
<script>
var vm = new Vue({
el: '.carousel',
data: {
index: 0,
time: '',
pics: [{
url: '#',
src: 'img/1.jpg',
title: '标题1',
on: true
},
{
url: '#',
src: 'img/2.jpg',
title: '标题2',
on: false
},
{
url: '#',
src: 'img/3.jpg',
title: '标题3',
on: false
},
{
url: '#',
src: 'img/4.jpg',
title: '标题4',
on: false
},
{
url: '#',
src: 'img/5.jpg',
title: '标题5',
on: false
}
]
},
methods: {
toggle: function(index) {
this.index = index;
this.pics[index].on = true;
for (var i = 0; i < this.pics.length; i++) {
if (i !== index)
this.pics[i].on = false;
}
},
mouseover: function() {
clearInterval(this.time);
},
mouseout: function() {
var that = this;
this.time = setInterval(function() {
if (that.index == that.pics.length - 1) {
that.index = 0;
that.pics[0].on = true;
that.pics[that.pics.length - 1].on = false;
} else {
++that.index;
that.pics[that.index].on = true;
that.pics[that.index - 1].on = false;
}
}, 3000)
}
},
computed: {
style: function() {
return {
marginLeft: this.index * (-100) + '%',
width: this.pics.length * 100 + '%'
}
},
},
mounted: function() {
this.mouseout();
}
});
</script>
</body>
</html>
实现效果如图:
这种轮播图原理是一串图片通过浮动拼在一起,利用marginLeft的位移作为动画实现的,比较容易实现,缺点是中间隔几个图的时候点击感觉比较晃,而且不是无缝轮播。
新版轮播图
接下来我们就来实现一下无缝轮播图,也就是新版B站首页所用的。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
li {
list-style-type: none;
}
.carousel {
max-width: 440px;
height: 220px;
position: relative;
overflow: hidden;
border-radius: 4px;
float: left;
}
.carousel .pic {
width: 440px;
height: 220px;
}
.carousel img {
width: 440px;
height: 220px;
}
.carousel .pic li {
position: absolute;
top: 0;
left: 0;
/* 这里一定要改成绝对定位 */
}
/* 标题过渡 */
.carousel .title li {
position: absolute;
bottom: 10px;
left: 10px;
transition: .5s;
z-index: 999999;
}
.carousel .title a {
color: white;
}
.carousel .trig {
position: absolute;
right: 35px;
bottom: 10px;
z-index: 999999;
}
.carousel .trig li {
float: left;
background-image: url(img/icons.png);
background-position: -855px -790px;
width: 18px;
height: 18px;
margin-left: 5px;
cursor: pointer;
}
.carousel .trig li:hover {
background-position: -919px -790px;
}
.on {
background-position: -855px -727px !important;
width: 18px;
height: 18px;
}
.show {
opacity: 1;
}
.hide {
opacity: 0;
}
</style>
</head>
<body>
<div class="carousel" @mouseover="mouseover" @mouseout="mouseout">
<ul class="pic" ref="pic">
<li v-for="(item,index) in pics"><a :href="pics[index].url"><img :src="pics[index].src"></a></li>
</ul>
<ul class="title">
<li v-for="(item,index) in pics" :class="pics[index].on?'show':'hide'"><a :href="pics[index].url">{{pics[index].title}}</a></li>
</ul>
<ul class="trig">
<li v-for="(item,index) in pics" :class="{on:pics[index].on}" @click="toggle(index)"></li>
</ul>
</div>
<script>
var vm = new Vue({
el: '.carousel',
data: {
index: 0,
time: '',
zindex: 1,
pics: [{
url: '#',
src: 'img/1.jpg',
title: '标题1',
on: true
},
{
url: '#',
src: 'img/2.jpg',
title: '标题2',
on: false
},
{
url: '#',
src: 'img/3.jpg',
title: '标题3',
on: false
},
{
url: '#',
src: 'img/4.jpg',
title: '标题4',
on: false
},
{
url: '#',
src: 'img/5.jpg',
title: '标题5',
on: false
}
]
},
methods: {
toggle: function(i) {
this.index = i;
this.pics[i].on = true;
for (let j = 0; j < this.pics.length; j++) {
if (j !== i)
this.pics[j].on = false;
}
this.zindex++;
this.$refs.pic.children[i].style.zIndex = this.zindex;
this.$refs.pic.children[i].style.transform = 'translate3d(0px,0px,0px)';
this.$refs.pic.children[i].style.transition = 'all 0.25s ease 0s';
if (i >= 1) {
//当前轮播图前面的全部向左移
for (let j = 0; j < i; j++) {
this.$refs.pic.children[j].style.transition = 'all 0.55s ease 0s';
this.$refs.pic.children[j].style.transform = 'translate3d(-440px,0px,0px)';
}
} else {
//点击第一个按钮,此时第一张图在最后一张图左边
this.$refs.pic.children[this.pics.length - 1].style.transition = 'all 0.55s ease 0s';
this.$refs.pic.children[this.pics.length - 1].style.transform = 'translate3d(440px,0px,0px)';
}
if (i < this.pics.length - 1) {
//当前轮播图后面的全部向右移
for (let j = i + 1; j < this.pics.length; j++) {
this.$refs.pic.children[j].style.transition = 'all 0.55s ease 0s';
this.$refs.pic.children[j].style.transform = 'translate3d(440px,0px,0px)';
}
} else {
//点击最后一个按钮,此时第一张图在最后一张图左边
this.$refs.pic.children[0].style.transition = 'all 0.55s ease 0s';
this.$refs.pic.children[0].style.transform = 'translate3d(-440px,0px,0px)';
}
},
mouseover: function() {
clearInterval(this.time);
//鼠标移入,第一张图在最后一张图左边
if (this.index == this.pics.length - 1) {
this.$refs.pic.children[0].style.transform = 'translate3d(-440px,0px,0px)';
}
//鼠标移入,第一张图在最后一张图左边
else if(this.index ==0){
this.$refs.pic.children[this.pics.length - 1].style.transform = 'translate3d(440px,0px,0px)';
}
},
mouseout: function() {
var that = this;
var i = that.index;
//鼠标移出,第一张图在最后一张图右边
if (i == that.pics.length - 1) {
that.$refs.pic.children[0].style.transform = 'translate3d(440px,0px,0px)';
}
//自动轮播
this.time = setInterval(function() {
that.zindex++;
if (i == that.pics.length - 1) {
i = 0;
} else {
++i
}
that.index = i;//必须储存index的值,否则值恒为0
that.$refs.pic.children[i].style.zIndex = that.zindex;
that.$refs.pic.children[i].style.transform = 'translate3d(0px,0px,0px)';
that.$refs.pic.children[i].style.transition = 'all 0.25s ease 0s';
that.pics[i].on = true;
//向左移动
if (i > 0) {
that.$refs.pic.children[i - 1].style.transition = 'all 0.55s ease 0s';
that.$refs.pic.children[i - 1].style.transform = 'translate3d(-440px,0px,0px)';
that.pics[i - 1].on = false;
} else {
that.$refs.pic.children[that.pics.length - 1].style.transition = 'all 0.55s ease 0s';
that.$refs.pic.children[that.pics.length - 1].style.transform = 'translate3d(-440px,0px,0px)';
that.pics[that.pics.length - 1].on = false;
}
//向右移动
if (i < that.pics.length - 1) {
that.$refs.pic.children[i + 1].style.transition = 'none 0s ease 0s';
that.$refs.pic.children[i + 1].style.transform = 'translate3d(440px,0px,0px)';
} else {
that.$refs.pic.children[0].style.transition = 'none 0s ease 0s';
that.$refs.pic.children[0].style.transform = 'translate3d(440px,0px,0px)';
}
}, 3000)
}
},
mounted: function() {
this.mouseout();
//初始状态,即0++++
for (let j = 1; j < this.pics.length; j++) {
this.$refs.pic.children[j].style.transform = 'translate3d(440px,0px,0px)'
}
this.$refs.pic.children[0].style.zIndex = '1';
}
});
</script>
</body>
</html>
这种轮播图比起上一种要复杂的多,但是看起来非常舒服,甚至比swiper的轮播图还要高档,给人的感觉就好像是两张图在相互切换,其他图在怎么变换根本看不出来。
根据我仔细的观察,分析出了原理,主要是通过translate3d变换位移,还需要加上叠放次序zindex,不然顺序会乱,你会看到其中一张图在过渡的时候压到其他图,这里的过渡要分开加,而不是写在CSS中,不是无脑加,第一张往最后一张图后面移动时不能有过渡动画,重点还要考虑第一张图和最后一张图的位置关系,这里一个过渡0.25s和一个过渡0.55s并不是没有道理,如果都设为0.55s可能会看到其它图的过渡惨杂进来
实现效果如图: