4

vue组件库

Slider 轮播图组件

基于Better-scroll的轮播组件,所以必须首先安装 better-scroll

// slider.vue
<template>
  <!-- 轮播图组件 -->
  <div class="slider" ref="slider">
    <!-- images -->
    <div class="slider-group" ref="sliderGroup">
      <slot></slot>
    </div>
    <!-- dots -->
    <div class="dots">
      <span class="dot-item"
            v-for="(item, index) in dots"
            :key="index"
            :class="{'active': currentDotIndex === index}"
      ></span>
    </div>
  </div>
</template>

<script>
import {addClass} from '@/common/js/Dom'
import BScroll from 'better-scroll'
export default {
  name: 'slider',
  props: {
    loop: {
      type: Boolean, // 循环播放
      default: true
    },
    autoPlay: {
      type: Boolean, // 自动播放
      default: true
    },
    interval: {
      type: Number, // 滚动的时间间隔
      default: 4000
    }
  },
  data() {
    return {
      dots: [],
      currentDotIndex: 0
    }
  },
  mounted() {
    setTimeout(() => {
      this._setSliderWidth()
      this._initDots()
      this._initSlider()
      if (this.autoPlay) {
        this._play()
      }
    }, 20)
    // 当窗口发生变化的时候
    window.addEventListener('resize', () => {
      if (!this.slider) {
        return false
      }
      this._setSliderWidth(true)
      this.slider.refresh()
    })
  },
  activated () {
    if (this.autoPlay) {
      this._play()
    }
  },
  deactivated () {
    clearTimeout(this.timer)
  },
  beforeDestroy () {
    clearTimeout(this.timer)
  },
  methods: {
    _setSliderWidth (isResize) {
      // 初始化宽度
      // 获取每一张图片DOM
      this.children = this.$refs.sliderGroup.children
      let width = 0
      let sliderWidth = this.$refs.slider.clientWidth // 每一张图片的宽度

      for (let i = 0; i < this.children.length; i++) {
        let child = this.children[i]
        addClass(child, 'slider-item') // 添加class

        child.style.width = sliderWidth + 'px' // 设置宽度
        width += sliderWidth // 求和算出总宽度
      }

      if (this.loop && !isResize) {
        width += 2 * sliderWidth // 循环增加
      }
      // 设置图片的直接容器的宽度
      this.$refs.sliderGroup.style.width = width + 'px'
    },
    _initSlider () {
      // 实例化一个 better-scroll对象
      this.slider = new BScroll(this.$refs.slider, {
        scrollX: true,
        scrollY: false,
        momentum: false, // 快速滑动不开启滑动惯性 ,默认式true
        snap: {
          loop: this.loop, // 为了支持循环轮播
          threshold: 0.3, // 表示可滚动到下一个的阈值
          speed: 400 // 轮播图切换的动画时间
        },
        click: true
      })
      // 一页图片滚动完毕之后触发
      this.slider.on('scrollEnd', () => {
        let pageIndex = this.slider.getCurrentPage().pageX

        this.currentDotIndex = pageIndex
        if (this.autoPlay) {
          // 用手拖的时候清除定时器
          clearTimeout(this.timer)
          this._play()
        }
      })
    },
    _initDots () {
      this.dots = new Array(this.children.length)
    },
    _play () {
      // 自动播放
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.slider.next()
      }, this.interval)
    }
  }
}
</script>

<style lang="stylus" scoped>
@import "../../common/stylus/varstyle.styl"

.slider
  min-height: 1px
  position relative
  .slider-group
    width: 100%
    position relative
    overflow hidden
    white-space nowrap
    .slider-item
      float left
      box-sizing border-box
      overflow: hidden
      text-align: center
      a
        display block
        width 100%
        overflow hidden
        text-align center
        img
          display block
          width 100%
  .dots
    position absolute
    left: 0px
    right: 0px
    bottom 8px
    text-align center
    font-size 0px
    .dot-item
      display inline-block
      margin 0px 4px
      width: 8px
      height: 8px
      border-radius 50%
      background $color-text-l
      &.active
        width: 12px
        border-radius 5px
        background $color-text-ll
</style>
使用
// 
<template>
  <div class="recommend-wrapper">
    // 【1】 这里的 v-if 必须写
    <div v-if="recommemds.length" class="slider-wrapper" ref="sliderWrapper">
      <slider>
        <div v-for="(item, index) in recommemds"
             :key="index"
            >
          <a :href="item.linkUrl">
            <img :src="item.picUrl" alt="">
          </a>
        </div>
      </slider>
    </div>
  </div>
</template>

Scroll 区域滚动组件

// scroll.vue

<template>
  <!-- 滚动区域组件 -->
  <div ref="wrapper">
    <slot></slot>
  </div>
</template>

<script type="text/ecmascript-6">
import BScroll from 'better-scroll'
export default {
  props: {
    probeType: {
      type: Number,
      default: 1
    },
    click: {
      type: Boolean,
      default: true
    },
    listenScroll: {
      type: Boolean,
      default: false
    },
    data: {
      type: Array,
      default: null
    },
    pullup: {
      type: Boolean,
      default: false
    },
    beforeScroll: {
      type: Boolean,
      default: false
    },
    refreshDelay: {
      type: Number,
      default: 20
    }
  },
  mounted () {
    setTimeout(() => {
      this._initScroll()
    }, 20)
  },
  methods: {
    _initScroll () {
      // 初始化
      if (!this.$refs.wrapper) {
        return
      }
      // 实例化一个对象
      this.scroll = new BScroll(this.$refs.wrapper, {
        probeType: this.probeType,
        click: this.click
      })
      // 如果监听
      if (this.listenScroll) {
        let me = this
        // 监听scroll事件
        this.scroll.on('scroll', (pos) => {
          // 派发一个scroll事件, 传出pos参数
          me.$emit('scroll', pos)
        })
      }

      if (this.pullup) {
        // 向下滚动监听时候滚动结束
        this.scroll.on('scrollEnd', () => {
          if (this.scroll.y <= (this.scroll.maxScrollY + 50)) {
            // 派发事件
            this.$emit('scrollToEnd')
          }
        })
      }

      if (this.beforeScroll) {
        // 监听滚动之前
        this.scroll.on('beforeScrollStart', () => {
          this.$emit('beforeScroll')
        })
      }
    },
    // 下面是代理了一些better-scroll的方法
    disable () {
      // 也就是说,调用当前组件的方法就是在调用better-scroll的原生的方法
      this.scroll && this.scroll.disable()
    },
    enable () {
      this.scroll && this.scroll.enable()
    },
    refresh () {
      this.scroll && this.scroll.refresh()
    },
    scrollTo () {
      this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
    },
    scrollToElement () {
      this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
    }
  },
  watch: {
    // 监听数据
    data () {
      // 自动刷新
      setTimeout(() => {
        this.refresh()
      }, this.refreshDelay)
    }
  }
}
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">

</style>
使用
// 必须通过css规定大小哦,并且需要设置overflow: hidden;
<scroll class="recommend-wrapper" :data="discList">
    <div>
        // 数据内容
    </div>
</scroll>


Meils
1.6k 声望157 粉丝

前端开发实践者


« 上一篇
Vue 全局API
下一篇 »
HTML5 之 SVG