Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.

TIP 👉 Strong wind knows strong grass, old and cold see after wither. Book of the Later Han by Fan Ye

preface

In our daily project development, we often write some ICONS, so we encapsulate this icon component.

Caroute diagram component

attribute

1. BannerList data array
  • Array to hold the information of the rotation picture
  • The object contains two properties, SRC and link
    • The SRC value is the image address
    • The value of link is the address where the link is opened by clicking on the image
2. Speed Animation duration
  • Unit: millisecond
  • Default value: 300
3. Interval Indicates the multicast interval
  • Unit: millisecond
  • Default value: 3000
4. DefaultIndex Indicates the index of the initially displayed multicast graph

Default value: 0

5. IndexType Bottom navigation style
  • The bottom navigation style value is dot or line
    • Dot dot (default)
    • The line dash

The sample

<template>
  <div class="banners-demo">
    <banners :bannerList="imgList" :speed="1000" :interval="5000" :defaultIndex="2" indexType="line"></banners>
  </div>
</template>
<script>
import BaseBanners from '@/components/base/banners/index.vue'
export default {
  name: 'bannersDemo',
  data () {
    return {
      imgList: [
        {
          src: '/static/img/banner1.png',
          link: 'http://www.baidu.com'
        },
        {
          src: '/static/img/banner2.gif',
          link: 'http://www.hao123.com'
        },
        {
          src: '/static/img/banner3.jpg'
        }
      ]
    }
  },
  methods: {},
  components: {
    Banners
  }
}
</script>
<style lang="scss" scoped>
.banners-demo{
  width: 700px;
  height: 400px;
  margin: 30px auto 0;
}
</style>

Copy the code

Realize the banner. Vue

<template>
  <div class="banners-container">
    <div class="banners-wrap" ref="bannersWrap">
      <div class="banner-item" v-for="item in banners" :key="item.src"
           :class="[item.animationClass]"
           :style="item.style"
           @click="linkHandle(item)">
      </div>
    </div>
    <div class="nav-wrap">
      <div class="nav-index-wrap" :class="[isStartNav && index === curIndex ? 'cur' : '']" v-for="(item, index) in bannerList" :key="item.src" @click="onChooseIndex(index)">
        <b class="nav-index" :class="indexClass">
          <span class="line-process" v-if="indexType === 'line'" :style="{transitionDuration: interval+'ms'}"></span>
        </b>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'banners'.props: {
    bannerList: {
      type: Array.default: () = >[]},// Animation length (milliseconds)
    speed: {
      type: Number.default: 300
    },
    // Multicast interval (ms)
    interval: {
      type: Number.default: 3000
    },
    // The index of the initial display of the multicast graph
    defaultIndex: {
      type: Number.default: 0
    },
    // Bottom navigation styles :dot, line, default :dot
    indexType: {
      type: String.default: 'dot'
    }
  },
  data () {
    const curIndex = (this.defaultIndex < 0 || this.defaultIndex >= this.bannerList.length) ? 0 : this.defaultIndex
    return {
      curIndex, // Current index
      lastIndex: null.// The index of the previous banner
      intervalId: null.// Timer ID
      isStart: false.// Whether to start the banner switch animation
      isStartNav: false.// Whether to start navigation animation
      isReverse: false // Whether the animation is reversed}},computed: {
    indexClass () {
      return 'nav-' + this.indexType
    },
    banners () {
      let list = this.bannerList
      let length = this.bannerList.length
      for (let i = 0; i < length; i++) {
        let animationClass = ' '
        let style = {
          animationDuration: this.speed + 'ms'.backgroundImage: `url('${list[i].src}') `
        }
        if (this.isStart) {
          if (this.isReverse) {
            if (i === this.curIndex) {
              animationClass = 'show-reverse'
            } else if (i === this.lastIndex) { // i === (this.curIndex + 1) % length)
              animationClass = 'hide-reverse'}}else {
            if (i === this.curIndex) {
              animationClass = 'show'
            } else if (i === this.lastIndex) { // (i === (this.curIndex === 0 ? length - 1 : this.curIndex - 1))
              animationClass = 'hide'}}}else {
          if (i === this.curIndex) {
            animationClass = 'cur'
          }
        }
        list[i].animationClass = animationClass
        list[i].style = style
      }
      return list
    }
  },
  mounted () {
    setTimeout(() = > { this.isStartNav = true }, 10)
    this.intervalId = setInterval(this.start, this.interval)
    this.addListener()
  },
  methods: {
    linkHandle (item) {
      if (item.link) {
        window.open(item.link)
      }
    },
    start () {
      this.isStart = true
      this.isReverse = false
      this.lastIndex = this.curIndex
      let maxIndex = this.bannerList.length - 1
      if (this.curIndex >= maxIndex) {
        this.curIndex = 0
      } else {
        this.curIndex++
      }
    },
    onSwipe (direction) {
      if (direction) {
        clearInterval(this.intervalId)
        this.lastIndex = this.curIndex
        this.isReverse = direction < 0
        this.curIndex += direction
        let listLength = this.bannerList.length
        if (this.curIndex >= listLength) {
          this.curIndex = 0
        } if (this.curIndex < 0) {
          this.curIndex = listLength - 1
        }
        this.isStart = true
        this.intervalId = setInterval(this.start, this.interval)
      }
    },
    onChooseIndex (index) {
      if (this.curIndex ! == index) {clearInterval(this.intervalId)
        this.lastIndex = this.curIndex
        this.curIndex = index
        this.isStart = true
        this.intervalId = setInterval(this.start, this.interval)
      }
    },
    addListener () {
      const bannersWrap = this.$refs.bannersWrap
      bannersWrap.addEventListener('touchstart'.this.touchStartHandler)
      bannersWrap.addEventListener('touchmove'.this.touchMoveHandler)
      bannersWrap.addEventListener('touchend'.this.touchEndHandler)
    },
    touchStartHandler (e) {
      this.startX = e.touches[0].pageX
      this.moveEndX = this.startX
    },
    touchMoveHandler (e) {
      this.moveEndX = e.changedTouches[0].pageX
    },
    touchEndHandler (e) {
      if (this.moveEndX - this.startX > 50) {
        this.onSwipe(-1)
        e.stopPropagation()
      } else if (this.moveEndX - this.startX < -50) {
        this.onSwipe(1)
        e.stopPropagation()
      }
    }
  },
  destroyed () {
    clearInterval(this.intervalId)
  }
}
</script>
<style lang="scss" scoped px2rem="false">$dotSize: 6px; .banners-container{ position: relative; height: 100%; } .banners-wrap{ position: relative; overflow: hidden; height: 100%; white-space: nowrap; background-color: #cdcdcd; .banner-item{ position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: #000 no-repeat center; background-size: cover; animation-timing-function: ease-in-out; z-index: 0; } .cur,.show,.show-reverse{ z-index: 2; } .hide, .hide-reverse{ z-index: 1; } .show{ animation-name: show-in; } .hide{ animation-name: show-out; transform: translate3d(-100%, 0, 0); } .show-reverse{ animation-name: show-in-reverse; } .hide-reverse{ animation-name: show-out-reverse; transform: translate3d(100%, 0, 0); } } .nav-wrap{ position: absolute; bottom: 14px; width: 100%; text-align: center; white-space: nowrap; line-height: $dotSize * 2; z-index: 10; .nav-index-wrap { display: inline-block; .nav-index { display: inline-block; vertical-align: middle; } .nav-dot{ margin: 5px 10px; width: $dotSize * 2; height: $dotSize * 2; border-radius: 50%; Background - color: rgba (0, 0, 5); } .nav-line{ margin: 5px; width: 40px; height: 2px; background-color: rgba(255, 255, 255, .5); .line-process { display: block; height: 100%; width: 0; background-color: #fff; transition: none; } } } .cur{ .nav-dot { background-color: rgba(255, 255, 255, .5); } .nav-line{ background-color: rgba(255, 255, 255, .5); .line-process { width: 100%; transition-property: width; transition-timing-function: ease; } } } } @keyframes show-in{ 0% { transform: translate3d(100%, 0, 0); } 100% { transform: translate3d(1px, 0, 0); } } @keyframes show-out{ 0% { transform: translate3d(1px, 0, 0); } 100% { transform: translate3d(-100%, 0, 0); } } @keyframes show-in-reverse{ 0% { transform: translate3d(-100%, 0, 0); } 100% { transform: translate3d(0, 0, 0); } } @keyframes show-out-reverse{ 0% { transform: translate3d(0, 0, 0); } 100% { transform: translate3d(100%, 0, 0); }}</style>
// Do not delete the following comment. It is used to determine whether mobile terminals are supported according to the isMobile configuration item in the configuration file. If not, comment out the style
/* [auto html command START {isMobile=false}] */
<style lang="scss" scoped>$dotSize: 8px; @media (max-width: $max-mobile-width) { .nav-wrap{ bottom: 10px; line-height: $dotSize * 2; /*no*/ .nav-index-wrap { .nav-dot { width: $dotSize * 2; /*no*/ height: $dotSize * 2; /*no*/ border-radius: 50%; /*no*/ } .nav-line { margin: 10px; width: 40px; height: 4px; } } } [data-dpr='1'] .nav-wrap{ line-height: $dotSize; /*no*/ .nav-dot{ width: $dotSize; /*no*/ height: $dotSize; /*no*/ } } [data-dpr='3'] .nav-wrap{ line-height: $dotSize * 3; /*no*/ .nav-dot{ width: $dotSize * 3; /*no*/ height: $dotSize * 3; /*no*/ } } }</style>
/* [auto html command END {isMobile=false}] */
Copy the code

Thanks for the comment section.

Hope to finish watching friends can give a thumbs-up, encourage once