简化的无缝轮播图

76 阅读1分钟

js部分


class Swiper {
    constructor(cfg) {
        const { duration, interval, container, direction, itemWidth } = cfg
        this.duration = duration
        this.direction = direction
        this.interval = interval
        this.container = container
        this.itemList = this.container.querySelectorAll('.slide-item')
        this.createPageItemList()
        this.len = this.itemList.length
        this.itemWidth = itemWidth || 360
        this.currentIndex = 0

        if (!this.len) return
        const cloneItem = this.itemList[0].cloneNode(true)
        this.cloneItem = cloneItem
        cloneItem.className = 'slide-item clone-item'
        this.len++
        this.container.appendChild(cloneItem)
        this.slideFunc = this.slideFunc.bind(this)
        this.timer = undefined
    }
    createPageItemList() {
        const ulElement = document.createElement('ul')
        ulElement.className = 'swiper-pagination'
        ulElement.id = 'pagination'

        const fragElement = document.createDocumentFragment()
        for (let i = 0; i < this.itemList.length; i++) {
            const liElement = document.createElement('li')
            liElement.className = 'pagination-item'
            liElement.innerHTML = "<i></i>"
            fragElement.appendChild(liElement)
        }
        ulElement.appendChild(fragElement)
        this.container.parentNode.appendChild(ulElement)
        this.pItemList = this.container.parentNode.querySelectorAll('.p-item')
    }
    setActiveItem() {
        this.itemList[this.currentIndex].className = 'slide-item active'
        this.pItemList[this.currentIndex].className = 'pagination-item active'
    }
    resetItem() {
        let c = 0
        if (this.direction === 'right') {
            c = this.currentIndex === 0 ? this.len - 2 : this.currentIndex - 1
        }
        else if (this.direction === 'left') {
            c = this.currentIndex === this.len - 2 ? 0 : this.currentIndex + 1
        }
        this.itemList[c].className = 'slide-item'
        this.pItemList[c].className = 'pagination-item'
    }
    init() {
        this.setActiveItem()
        this.startSlide()
        this.touchMoveBind()
    }
    slideFunc() {
        if (this.direction === 'right') this.currentIndex++
        else this.currentIndex--
        if (this.currentIndex < 0) this.currentIndex = 0
        else if (this.currentIndex === this.len - 1) {
            this.cloneItem.style.opacity = 1
            this.container.style.left = `-${this.currentIndex * this.itemWidth}px`
            let tm = undefined
            const that = this
            tm = setTimeout(() => {
                that.container.style.left = `0px`
                this.container.style.transitionDuration = '0ms'
                this.cloneItem.style.opacity = 0
                if (tm) {
                    clearTimeout(tm)
                    return
                }
            }, this.duration)
            this.currentIndex = 0
        }
        else {
            this.container.style.transitionDuration = `${this.duration}ms`
            this.container.style.left = `-${this.currentIndex * this.itemWidth}px`
        }
        this.setActiveItem()
        this.resetItem()
        if (this.timer) clearTimeout(this.timer)
        this.startSlide()
    }
    startSlide() {
        this.timer = setTimeout(this.slideFunc, this.interval);
    }
    touchMoveBind() {
        let startX = 0, startY = 0;
        let moveEndX = 0, moveEndY = 0;
        let timerLeft = undefined, timerRight = undefined
        const disU = 40, disL = -40, t = 90
        const that = this
        this.container.addEventListener('touchstart', (e) => {
            const changedTouches = e.changedTouches[0]
            startX = changedTouches.pageX;
            startY = changedTouches.pageY;
        })

        this.container.addEventListener('touchmove', (e) => {
            const changedTouches = e.changedTouches[0]
            moveEndX = changedTouches.pageX;
            moveEndY = changedTouches.pageY;
            const distanceX = moveEndX - startX,
                distanceY = moveEndY - startY
            if (Math.abs(distanceX) > Math.abs(distanceY)) {
                if (distanceX > disU) {
                    if (timerLeft) clearTimeout(timerLeft)
                    timerLeft = setTimeout(() => {
                        that.direction = 'left'
                        that.slideFunc()
                    }, t)
                }
                else if (distanceX < disL) {
                    if (timerRight) clearTimeout(timerRight)
                    timerRight = setTimeout(() => {
                        that.direction = 'right'
                        that.slideFunc()
                    }, t)
                }
            }
        })
    }
}

const sw = new Swiper({
    duration: 300,
    interval: 2966,
    container: document.querySelector('.slider'),
    direction: 'right',
    itemWidth: 360
})

sw.init()

let gTimer
window.onresize = () => {
    if (gTimer) clearTimeout(gTimer)
    gTimer = setTimeout(() => {
        sw.itemWidth = 'xxx' // 根据resize设置
        if (sw.timer) clearInterval(sw.timer)
        sw.startSlide()
    }, 900)
}

html部分

  <div class="slider">
    <div class="item-slide"><img src="images/pic1.png" /></div>
    <div class="item-slide"><img src="images/pic2.png"/></div>
    <div class="item-slide"><img src="images/pic3.png" /></div>
    <div class="item-slide"><img src="images/pic.p4ng"/></div>
    <div class="item-slide"><img src="images/pic5.png"/></div>
  </div>

css

.slider-wrap-area {
  position: relative;
  overflow: hidden;
  .slider {
    min-width: 960px;
    transform: translateX(1px);
    transition: all 0.3s ease-out;  //与js部分无缝地方的duration对应
    padding: 9px;
    position: relative;
    display: flex;
    left: 0;
    .item-slide {
      display: inline-block;
      min-width: 360px;
      transform: scale(0.93);
      &.active {
        transform: scale(1);
      }
      &.scale {
        transform: scale(0.93);
      }
      &.clone-item {
        transform: scaleX(0.93);
        opacity: 0;
      }
      span {
        display: block;
        text-align: center;
        color: #fff;
        font-size: 22px;
        margin-bottom: 14px;
      }
      img {
        width: 100%;
      }
    }
  }
  .swiper-pagination {
    display: flex;
    justify-content: center;
    position: absolute;
    bottom: 36px;
    width: 100%;
    li {
      list-style-type: none;
      margin-left: 7px;
      margin-right: 7px;
      i {
        display: block;
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background-color: rgba(255, 255, 255, 0.3);
      }
      &.active {
        i {
          background-color: rgba(255, 255, 255, 1);
        }
      }
    }
  }
}