主要html架构
<!- slider组件 ->
<div class="slider-wrapper" ref="sliderWrapper">
<div class="slider-ul" ref="sliderUl">
<div class="slider-li" v-for="(item,index) in imgDatas">
<a href="#">
<img src="#">
</a>
</div>
</div>
</div>
解释:
- slider-wrapper是外层容器,它的宽度是更外层容器的宽度,比如在父组件中
<!- 父组件 ->
<div class="parent-box">
<!- slider-wrapper继承,撑满parent-box的宽度 -->
<slider></slider>
</div>
- slider-ul是图片组ul的宽度,宽度是slider-li的数量 * slider-li的width
- slider-li是一个图片项
- imgDatas是图片的数据数组
主要CSS代码
/* slider组件的主要CSS代码 */
.slider-wrapper {
position: relative;
width: 100%; /*撑满父容器*/
height: 100%; /*撑满父容器*/
min-height: 1px;
overflow: hidden;
}
.slider-ul {
/* mounted的时候设定ul的宽度,设定方法是100% x 多少个图片item,如5个图片项则是500% */
/* 如果是假数据进行样式设定调试,可以先设定width为多少个100% */
position: relative;
white-space: nowrap;
overflow: hidden; /*清除浮动*/
height: 100%;
}
.slider-li {
/* 同样是 mounted时设定一个item的宽度,宽度要和slider-wrapper的宽度一样,则 500% * 0.2 = 100% */
/* 同样是假数据的样式调试的时候,可以先设定width,如slider-wrapper为100%,slider-ul为500%,即有五张图片,此时设定slider-li的width为20%,500 * 0.2 = 100,则和slider-wrppaer宽度一致 */
height: 100%;
float: left; /*要设置浮动*/
box-sizing: border-box;
overflow: hidden;
}
.slider-li a {
overflow: hidden;
width: 100%;
height: 100%;
display: block;
}
.slider-li img {
width: 100%;
height: 100%;
display: block;
}
组件主要部分
- 安装:npm install better-scroll --save
- 在slider组件中引入:import BScroll from ‘better-scroll’
// props,父组件传入子组件的参数
props: {
loop: { //是否循环播放
type: Boolean,
default: true
},
autoPlay: { //是否自动播放
type: Boolean,
default: true
},
interVal: { //轮播一张图片的时间
type: Number,
default: 3000
},
imgDatas: { //传入的imgDatas数据
type: Array,
default: []
}
}
//主要内置数据
data() {
return {
currentPageIndex: 0 //记录当前是哪一张轮播图图片,下标从0开始,即第一张
}
}
//methods
methods:{
//第一步,根据传入的imgDatas初始化slider-ul,slider-li的宽度,为百分比
//注意,better-scroll在初始化时,当你设定了loop的时候,会在前后自动增加2张图片,例如5张图片会变成7张
//由于这是第一步,暂时没有初始化better-scroll,所以获取children的时候,只是5张图片,props的loop为true时,要加多两个,然后设定ul,li的宽度
_setUlWidth() {
this.children = this.$refs.sliderUl.children
let childrenLength = this.loop ? this.children.length + 2 : this.children.length
this.$refs.sliderUl.style.width = childrenLength * 100 + '%'
for (var i = 0; i < this.children.length; i++) {
this.children[i].style.width = 100 / childrenLength + '%'
}
},
//第二步,初始化better-scroll
_initSlider() {
let that = this
this.slider = new BScroll(this.$refs.sliderWrapper, {
scrollX: true,
scrollY: false,
momentum: false,
snap: {
loop: this.loop,
threshold: 0.3,
speed: 400
},
probeType: 2
})
//监听scroll结束的时候,赋值更新currentPageIndex
this.slider.on('scrollEnd', () => {
clearInterval(that.timer)
that.currentPageIndex = that.slider.getCurrentPage().pageX
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
that._setAutoplay()
})
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
//无缝
this.checkScroll(childrenLength,this.$refs.sliderWrapper.offsetWidth)
},
//第三步,设置自动播放
//这一步不需要重新设定currentPageIndex ,因为转到下一页时触发了scrollEnd事件,已经自动赋值更新
_setAutoplay() {
let goToIndex = this.currentPageIndex + 1
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
//设置右滑到最后一张的无缝切换,返回到第一张
if (goToIndex >= childrenLength) {
goToIndex = 0
}
this.timer = setInterval(() => {
this.slider.goToPage(goToIndex, 0, 400)
}, this.interVal)
},
//监听滑事件
checkScroll(childrenLength,itemWidth) {
let that = this
this.slider.on('scroll', () => {
clearInterval(that.timer)
let leftScroll = parseInt(that.$refs.sliderUl.style['transform'].substring(10, 15))
let left = -1 * itemWidth
let right = left * childrenLength
if (leftScroll >left) {
that.slider.goToPage(childrenLength, 0, 400)
}else if(leftScroll < right) {
that.slider.goToPage(1, 0, 400)
}
})
}
},
mounted() {
setTimeout(() => {
this._setUlWidth()
this._initSlider()
this._setAutoplay()
}, 20)
window.addEventListener('resize', () => {
if (!this.slider) {
return
}
this._setUlWidth()
})
}
这样已经可以轮播了哦,更详细的样式和功能代码看下面的源代码
源代码
使用说明:
<div style="width:400px;height:280px;">
<slider :imgDatas="imgDatas"></slider>
</div>
imgDatas: [
{ imgSrc: require("./images/1.jpg"), linkUrl: '#' },
{ imgSrc: require("./images/2.jpg"), linkUrl: '#' },
{ imgSrc: require("./images/3.jpg"), linkUrl: '#' },
{ imgSrc: require("./images/4.jpg"), linkUrl: '#' },
]
<template>
<div class="slider-wrapper" ref="sliderWrapper">
<div class="slider-ul" ref="sliderUl">
<div class="slider-li" v-for="(item,index) in imgDatas" :key="index">
<a :href="item.linkUrl">
<img :src="item.imgSrc">
</a>
</div>
</div>
<div class="dots">
<span
:key="'b'+index"
v-for="(item,index) in imgDatas"
:class="{'dot-active' : currentPageIndex == index}"
@click="linkToPage(index)"
></span>
</div>
<div class="arrow left-arrow" @click="scrollbtnEvent('left')">
<span class="iconfont icon-xiangzuo"></span>
</div>
<div class="arrow right-arrow" @click="scrollbtnEvent('right')">
<span class="iconfont icon-xiangyou-copy"></span>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
props: {
loop: {
type: Boolean,
default: true
},
autoPlay: {
type: Boolean,
default: true
},
interVal: {
type: Number,
default: 3000
},
imgDatas: {
type: Array,
default: []
}
},
data() {
return {
currentPageIndex: 0
}
},
mounted() {
setTimeout(() => {
this._setUlWidth()
this._initSlider()
this._setAutoplay()
}, 20)
window.addEventListener('resize', () => {
if (!this.slider) {
return
}
this._setUlWidth()
})
},
methods: {
//初始化wrapper的宽度
_setUlWidth() {
this.children = this.$refs.sliderUl.children
let childrenLength = this.loop ? this.children.length + 2 : this.children.length
this.$refs.sliderUl.style.width = childrenLength * 100 + '%'
for (var i = 0; i < this.children.length; i++) {
this.children[i].style.width = 100 / childrenLength + '%'
}
},
//播放
_setAutoplay() {
let goToIndex = this.currentPageIndex + 1
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
if (goToIndex >= childrenLength) {
goToIndex = 0
}
this.timer = setInterval(() => {
this.slider.goToPage(goToIndex, 0, 400)
}, this.interVal)
},
//初始化better-scroll
_initSlider() {
let that = this
this.slider = new BScroll(this.$refs.sliderWrapper, {
scrollX: true,
scrollY: false,
momentum: false,
snap: {
loop: this.loop,
threshold: 0.3,
speed: 400
},
probeType: 2
})
//监听scroll结束的时候,赋值更新currentPageIndex
this.slider.on('scrollEnd', () => {
clearInterval(that.timer)
that.currentPageIndex = that.slider.getCurrentPage().pageX
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
that._setAutoplay()
})
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
//左滑到最左还想轮播
this.checkScroll(childrenLength,this.$refs.sliderWrapper.offsetWidth)
},
//监听滑事件
checkScroll(childrenLength,itemWidth) {
let that = this
this.slider.on('scroll', () => {
clearInterval(that.timer)
let leftScroll = parseInt(that.$refs.sliderUl.style['transform'].substring(10, 15))
let left = -1 * itemWidth
let right = left * childrenLength
if (leftScroll >left) {
that.slider.goToPage(childrenLength, 0, 400)
}else if(leftScroll < right) {
that.slider.goToPage(1, 0, 400)
}
})
},
//向左向右
scrollbtnEvent(type) {
clearInterval(this.timer)
let childrenLength = this.loop ? this.children.length - 2 : this.children.length
let goIndex = (type == 'left') ? this.currentPageIndex - 1 : this.currentPageIndex + 1
if (type == 'left') {
if (goIndex < 0) {
goIndex = childrenLength-1
}
} else {
if (goIndex >= childrenLength) {
goIndex = 0
}
}
this.slider.goToPage(goIndex, 0, 400)
},
//按小圆圈
linkToPage(index) {
this.slider.goToPage(index, 0, 400)
}
}
}
</script>
<style>
.slider-wrapper {
position: relative;
width: 100%;
height: 100%;
min-height: 1px;
overflow: hidden;
}
.dots {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0.1rem;
display: flex;
flex-direction: row;
}
.dots span {
cursor: pointer;
display: block;
width: 0.1rem;
height: 0.1rem;
border-radius: 0.05rem;
background: #CCCCCC;
margin-right: 0.05rem;
}
.dot-active {
width: 0.2rem !important;
background: #fff !important;
}
.arrow {
display: flex;
align-items: center;
position: absolute;
top: 0;
cursor: pointer;
color: #333;
opacity: 0.4;
font-size: 0.3rem;
width: 0.7rem;
height: 100%;
}
.arrow:hover {
opacity: 1;
background-image: linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);
color: #fff;
}
.left-arrow {
left: 0;
}
.left-arrow span {
margin-left: 0.2rem;
}
.right-arrow {
justify-content: flex-end;
right: 0;
}
.right-arrow span {
margin-right: 0.2rem;
}
.slider-ul {
position: relative;
white-space: nowrap;
overflow: hidden;
height: 100%;
}
.slider-li {
/* width: 20%; */
height: 100%;
float: left;
box-sizing: border-box;
overflow: hidden;
}
.slider-li a {
overflow: hidden;
width: 100%;
height: 100%;
display: block;
}
.slider-li img {
width: 100%;
height: 100%;
display: block;
}
@media screen and ( max-width : 500px ) {
.arrow{
display: none;
}
}
</style>