vue项目中用better-scroll制作轮播图

主要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>

解释:

  1. slider-wrapper是外层容器,它的宽度是更外层容器的宽度,比如在父组件中
<!- 父组件 ->
<div class="parent-box">
	<!- slider-wrapper继承,撑满parent-box的宽度 -->
	<slider></slider> 
</div>
  1. slider-ul是图片组ul的宽度,宽度是slider-li的数量 * slider-li的width
  2. slider-li是一个图片项
  3. 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;
}

组件主要部分

  1. 安装:npm install better-scroll --save
  2. 在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>

猜你喜欢

转载自blog.csdn.net/qq_40816360/article/details/84582676
今日推荐