vue移动音乐app开发学习:轮播图组件的开发

Posted _林冲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue移动音乐app开发学习:轮播图组件的开发相关的知识,希望对你有一定的参考价值。

本系列文章是为了记录学习中的知识点,便于后期自己观看。如果有需要的同学请登录慕课网,找到Vue 2.0 高级实战-开发移动端音乐WebApp进行观看,传送门

完成后的页面状态以及项目结构如下:

一:创建轮播图组件slider.vue

1:在src/base下新建base文件夹,然后创建silder.vue:

<template>
  <div class="slider" ref="slider">
    <div class="slider-group" ref="sliderGroup">
      <slot>
      </slot>
    </div>
    <div class="dots">
      <span class="dot" :class="{active: currentPageIndex === index }" v-for="(item, index) in dots"></span>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
  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: [],
        currentPageIndex: 0
      }
    },
    mounted() {
      setTimeout(() => {
        this._setSliderWidth()
        this._initDots()
        this._initSlider()

        if (this.autoPlay) {
          this._play()
        }
      }, 20)

      window.addEventListener(\'resize\', () => {
        if (!this.slider) {
          return
        }
        this._setSliderWidth(true)
        this.slider.refresh()
      })
    },
    activated() {
      if (this.autoPlay) {
        this._play()
      }
    },
    deactivated() {
      clearTimeout(this.timer)
    },
    beforeDestroy() {
      clearTimeout(this.timer)
    },
    methods: {
      _setSliderWidth(isResize) {
        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\')

          child.style.width = sliderWidth + \'px\'
          width += sliderWidth
        }
        if (this.loop && !isResize) {
          width += 2 * sliderWidth
        }
        this.$refs.sliderGroup.style.width = width + \'px\'
      },
      _initSlider() {
        this.slider = new BScroll(this.$refs.slider, {
          scrollX: true,
          scrollY: false,
          momentum: false,
          snap: true,
          snapLoop: this.loop,
          snapThreshold: 0.3,
          snapSpeed: 400
        })

        this.slider.on(\'scrollEnd\', () => {
          let pageIndex = this.slider.getCurrentPage().pageX
          if (this.loop) {
            pageIndex -= 1
          }
          this.currentPageIndex = pageIndex

          if (this.autoPlay) {
            this._play()
          }
        })

        this.slider.on(\'beforeScrollStart\', () => {
          if (this.autoPlay) {
            clearTimeout(this.timer)
          }
        })
      },
      _initDots() {
        this.dots = new Array(this.children.length)
      },
      _play() {
        let pageIndex = this.currentPageIndex + 1
        if (this.loop) {
          pageIndex += 1
        }
        this.timer = setTimeout(() => {
          this.slider.goToPage(pageIndex, 0, 400)
        }, this.interval)
      }
    }
  }
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">
  @import "~common/stylus/variable"

  .slider
    min-height: 1px
    .slider-group
      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-decoration: none
        img
          display: block
          width: 100%
    .dots
      position: absolute
      right: 0
      left: 0
      bottom: 12px
      text-align: center
      font-size: 0
      .dot
        display: inline-block
        margin: 0 4px
        width: 8px
        height: 8px
        border-radius: 50%
        background: $color-text-l
        &.active
          width: 20px
          border-radius: 5px
          background: $color-text-ll
</style>

  

 

2:组件中会含有addclass和hasclass的操作,但是这里没有用jquery,而是用原生的js封装了这两个方法。在src/common/js下新建dom.js:

export function hasClass(el, className) {
  let reg = new RegExp(\'(^|\\\\s)\' + className + \'(\\\\s|$)\')
  return reg.test(el.className)
}

export function addClass(el, className) {
  if (hasClass(el, className)) {
    return
  }

  let newClass = el.className.split(\' \')
  newClass.push(className)
  el.className = newClass.join(\' \')
}

 

3:页面的数据是用jsonp跨域请求qq音乐上的数据。github地址:传送门。接下来我们在src/common/js下新建jsonp.js,用来封装公共的jsonp方法:

import originJsonp from \'jsonp\'

export default function jsonp(url, data, option) {
  url += (url.indexOf(\'?\') < 0 ? \'?\' : \'&\') + param(data)

  return new Promise((resolve, reject) => {
    originJsonp(url, option, (err, data) => {
      if (!err) {
        resolve(data)
      } else {
        reject(err)
      }
    })
  })
}

export function param(data) {
  let url = \'\'
  for (var k in data) {
    let value = data[k] !== undefined ? data[k] : \'\'
    url += \'&\' + k + \'=\' + encodeURIComponent(value)
  }
  return url ? url.substring(1) : \'\'
}

  

 4:当我们异步请求数据的时候,一般都会有一些公共的参数,所以我们可以将这些公共的参数定义为常量。在src/api下新建config.js:

export const commonParams = {
  g_tk: 1928093487,
  inCharset: \'utf-8\',
  outCharset: \'utf-8\',
  notice: 0,
  format: \'jsonp\'
}

export const options = {
  param: \'jsonpCallback\'
}

export const ERR_OK = 0

 

4:定义获取轮播图数据的文件。在src/api下新建recommend.js:

import jsonp from \'common/js/jsonp\'
import {commonParams, options} from \'./config\'

export function getRecommend() {
  const url = \'https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg\'

  const data = Object.assign({}, commonParams, {
    platform: \'h5\',
    uin: 0,
    needNewCode: 1
  })

  return jsonp(url, data, options)
}

 

5:修改recommend.vue:

<template>
  <div class="recommend" ref="recommend">
   <div class="recommend-content">
     <div v-if="recommends.length" class="slider-wrapper" ref="sliderWrapper">
      <slider>
        <div v-for="item in recommends">
          <a :href="item.linkUrl">
             <img class="needsclick" @load="loadImage" :src="item.picUrl">
          </a>
        </div>
      </slider>
    </div>
  </div>
   </div>
</template>

<script type="text/ecmascript-6">
  import Slider from \'base/slider/slider\'
  import {getRecommend} from \'api/recommend\'
  import {ERR_OK} from \'api/config\'

  export default {
    data() {
      return {
        recommends: []
      }
    },
    created() {
      this._getRecommend()
    },
    methods: {
      _getRecommend() {
        getRecommend().then((res) => {
          if (res.code === ERR_OK) {
            this.recommends = res.data.slider
          }
        })
      },
      loadImage() {
        if (!this.checkloaded) {
          this.checkloaded = true
          this.$refs.scroll.refresh()
        }
      }
    },
    components: {
      Slider
    }
  }
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">
@import "~common/stylus/variable"

  .recommend
    position: fixed
    width: 100%
    top: 88px
    bottom: 0
    .recommend-content
      height: 100%
      overflow: hidden
      .slider-wrapper
        position: relative
        width: 100%
        overflow: hidden
      .recommend-list
        .list-title
          height: 65px
          line-height: 65px
          text-align: center
          font-size: $font-size-medium
          color: $color-theme
        .item
          display: flex
          box-sizing: border-box
          align-items: center
          padding: 0 20px 20px 20px
          .icon
            flex: 0 0 60px
            width: 60px
            padding-right: 20px
          .text
            display: flex
            flex-direction: column
            justify-content: center
            flex: 1
            line-height: 20px
            overflow: hidden
            font-size: $font-size-medium
            .name
              margin-bottom: 10px
              color: $color-text
            .desc
              color: $color-text-d
      .loading-container
        position: absolute
        width: 100%
        top: 50%
        transform: translateY(-50%)
</style>

 

以上是关于vue移动音乐app开发学习:轮播图组件的开发的主要内容,如果未能解决你的问题,请参考以下文章

Vue实现音乐播放器:轮播图组件

VUE移动端音乐APP学习二十:搜索框组件开发

VUE移动端音乐APP学习十七:歌单详情页组件开发

为啥vue移动端轮播图的组件安装后没法使用?

Vue组件开发--轮播图的实现

《移动应用开发》实验报告——轮播图