slide.vue 6.3 KB
Newer Older
M
init  
miaodian 已提交
1 2 3
<template>
  <div class="cube-slide" ref="slide">
    <div class="cube-slide-group" ref="slideGroup">
4
      <slot>
A
AmyFoxFN 已提交
5
        <cube-slide-item v-for="(item, index) in data" :key="index" @click.native="clickItem(item, index)" :item="item"></cube-slide-item>
6
      </slot>
M
init  
miaodian 已提交
7 8
    </div>
    <div class="cube-slide-dots">
D
dolymood 已提交
9
      <slot name="dots" :current="currentPageIndex" :dots="dots">
10
        <span :class="{active: currentPageIndex === index}" v-for="(item, index) in dots" :key="index"></span>
D
dolymood 已提交
11
      </slot>
M
init  
miaodian 已提交
12 13 14 15 16
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
D
dolymood 已提交
17
  import CubeSlideItem from './slide-item.vue'
M
init  
miaodian 已提交
18 19 20 21
  import BScroll from 'better-scroll'

  const COMPONENT_NAME = 'cube-slide'
  const EVENT_CHANGE = 'change'
A
AmyFoxFN 已提交
22
  const EVENT_SELECT = 'click'
M
init  
miaodian 已提交
23 24 25 26

  export default {
    name: COMPONENT_NAME,
    props: {
27 28 29 30 31 32
      data: {
        type: Array,
        default() {
          return []
        }
      },
D
dolymood 已提交
33 34 35 36
      initialIndex: {
        type: Number,
        default: 0
      },
M
init  
miaodian 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
      loop: {
        type: Boolean,
        default: true
      },
      autoPlay: {
        type: Boolean,
        default: true
      },
      interval: {
        type: Number,
        default: 4000
      },
      threshold: {
        type: Number,
        default: 0.3
      },
      speed: {
        type: Number,
        default: 400
D
dolymood 已提交
56 57 58 59
      },
      allowVertical: {
        type: Boolean,
        default: false
M
init  
miaodian 已提交
60 61 62 63 64
      }
    },
    data() {
      return {
        dots: 0,
D
dolymood 已提交
65 66 67
        currentPageIndex: this.initialIndex || 0
      }
    },
68 69 70 71 72 73 74 75
    created() {
      const needRefreshProps = ['data', 'loop', 'autoPlay', 'threshold', 'speed', 'allowVertical']
      needRefreshProps.forEach((key) => {
        this.$watch(key, () => {
          this.refresh()
        })
      })
    },
D
dolymood 已提交
76 77 78 79 80
    watch: {
      initialIndex(newIndex) {
        if (newIndex !== this.currentPageIndex) {
          this.slide && this.slide.goToPage(newIndex)
        }
M
init  
miaodian 已提交
81 82 83
      }
    },
    methods: {
A
AmyFoxFN 已提交
84
      clickItem(item, index) {
85 86
        this.$emit(EVENT_SELECT, item, index)
      },
M
init  
miaodian 已提交
87
      refresh() {
D
dolymood 已提交
88
        this.slide && this.slide.destroy()
D
dolymood 已提交
89
        clearTimeout(this._timer)
D
dolymood 已提交
90 91 92 93
        this.$nextTick(() => {
          if (this.slide === null) {
            return
          }
D
dolymood 已提交
94 95 96
          if (this.slide !== undefined) {
            this.currentPageIndex = 0
          }
D
dolymood 已提交
97 98 99 100 101 102 103 104 105 106 107
          this.dots = 0
          this._setSlideWidth()
          this._initDots()
          this._initSlide()

          if (this.autoPlay) {
            this._play()
          }
        })
      },
      _refresh() {
M
init  
miaodian 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        this._setSlideWidth(true)
        this.slide.refresh()
      },
      _setSlideWidth(isResize) {
        this.children = this.$refs.slideGroup.children

        let width = 0
        let slideWidth = this.$refs.slide.clientWidth
        for (let i = 0; i < this.children.length; i++) {
          let child = this.children[i]
          child.style.width = slideWidth + 'px'
          width += slideWidth
        }
        if (this.loop && !isResize) {
          width += 2 * slideWidth
        }
        this.$refs.slideGroup.style.width = width + 'px'
      },
      _initSlide() {
        this.slide = new BScroll(this.$refs.slide, {
          scrollX: true,
          scrollY: false,
          momentum: false,
131
          bounce: false,
D
dolymood 已提交
132
          eventPassthrough: this.allowVertical ? 'vertical' : '',
M
init  
miaodian 已提交
133 134 135 136 137
          snap: {
            loop: this.loop,
            threshold: this.threshold,
            speed: this.speed
          },
D
dolymood 已提交
138 139
          click: true,
          observeDOM: false
M
init  
miaodian 已提交
140 141
        })

D
dolymood 已提交
142 143
        this.slide.goToPage(this.currentPageIndex, 0, 0)

M
init  
miaodian 已提交
144 145
        this.slide.on('scrollEnd', this._onScrollEnd)

D
dolymood 已提交
146 147
        window.removeEventListener('touchend', this._touchEndEvent, false)
        this._touchEndEvent = () => {
M
init  
miaodian 已提交
148 149 150
          if (this.autoPlay) {
            this._play()
          }
D
dolymood 已提交
151 152
        }
        window.addEventListener('touchend', this._touchEndEvent, false)
M
init  
miaodian 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

        this.slide.on('beforeScrollStart', () => {
          if (this.autoPlay) {
            clearTimeout(this._timer)
          }
        })
      },
      _onScrollEnd() {
        let pageIndex = this.slide.getCurrentPage().pageX
        if (this.currentPageIndex !== pageIndex) {
          this.currentPageIndex = pageIndex
          this.$emit(EVENT_CHANGE, this.currentPageIndex)
        }

        if (this.autoPlay) {
          this._play()
        }
      },
      _initDots() {
        this.dots = new Array(this.children.length)
      },
      _play() {
        clearTimeout(this._timer)
        this._timer = setTimeout(() => {
D
dolymood 已提交
177
          this.slide.next()
M
init  
miaodian 已提交
178 179 180 181 182 183
        }, this.interval)
      },
      _deactivated() {
        clearTimeout(this._timer)
        clearTimeout(this._resizeTimer)
        window.removeEventListener('resize', this._resizeHandler)
D
dolymood 已提交
184
        window.removeEventListener('touchend', this._touchEndEvent, false)
M
init  
miaodian 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198
      },
      _resizeHandler() {
        if (!this.slide) {
          return
        }
        clearTimeout(this._resizeTimer)
        this._resizeTimer = setTimeout(() => {
          if (this.slide.isInTransition) {
            this._onScrollEnd()
          } else {
            if (this.autoPlay) {
              this._play()
            }
          }
D
dolymood 已提交
199
          this._refresh()
M
init  
miaodian 已提交
200 201 202 203
        }, 60)
      }
    },
    mounted() {
D
dolymood 已提交
204
      this.refresh()
M
init  
miaodian 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218

      window.addEventListener('resize', this._resizeHandler)
    },
    activated() {
      if (this.autoPlay) {
        this._play()
      }
      window.addEventListener('resize', this._resizeHandler)
    },
    deactivated() {
      this._deactivated()
    },
    destroyed() {
      this._deactivated()
219 220 221 222
      if (this.slide) {
        this.slide.destroy()
        this.slide = null
      }
D
dolymood 已提交
223 224 225
    },
    components: {
      CubeSlideItem
M
init  
miaodian 已提交
226 227 228 229 230
    }
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">
D
dolymood 已提交
231
  @require "../../common/stylus/variable.styl"
M
init  
miaodian 已提交
232
  .cube-slide
A
AmyFoxFN 已提交
233
    position: relative
M
init  
miaodian 已提交
234
    min-height: 1px
A
AmyFoxFN 已提交
235
    height: 100%
M
init  
miaodian 已提交
236 237 238

  .cube-slide-group
    position: relative
A
AmyFoxFN 已提交
239
    height: 100%
M
init  
miaodian 已提交
240 241 242 243 244 245 246 247 248
    overflow: hidden
    white-space: nowrap

  .cube-slide-dots
    position: absolute
    bottom: 2px
    right: 0
    left: 0
    padding: 0 6px
A
AmyFoxFN 已提交
249
    font-size: 0
M
init  
miaodian 已提交
250 251 252 253
    text-align: center
    transform: translateZ(1px)
    > span
      display: inline-block
D
dolymood 已提交
254
      vertical-align: bottom
M
init  
miaodian 已提交
255 256 257 258 259 260 261
      margin: 0 1px
      width: 10px
      height: 1px
      background: $slide-dot-bgc
      &.active
        background: $slide-dot-active-bgc
</style>