vue music-抓取歌单列表数据(渲染轮播图)

下载安装新依赖

babel-runtime:对es6语法进行转译
fastclick:对移动端进行点击300毫秒延迟 ,,取消掉
babel-polyfill:API

vue music-抓取歌单列表数据(渲染轮播图)_第1张图片

先添加,在npm install

main.js

import 'babel-polyfill'
import Vue from 'vue'
import App from './App'
import router from './router'
import fastclick from 'fastclick'

import 'common/stylus/index.styl'


Vue.config.productionTip = false

// 取消点击300毫秒的延迟
fastclick.attach(document.body) 

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: ''
})

头部栏引用header组件

1:





m-header。vue

2:在app.vue





二:导入歌手页面,搜索页面,排行榜,推荐页面

1:先在index.js入口注册这4个组件

import Reacommed from 'components/reacommed/reacommed'
import Search from 'components/search/search'
import Singer from 'components/singer/singer'
import Rank from 'components/rank/rank'

2:配置url

export default new Router({
  routes: [
    {
      path: '/reacommed',
      component:Reacommed
    },
    {
        path:'/singer',
        component:Singer
    },
    {
        path:'/rank',
        component:Rank
    },
    {
        path:'/search',
        component:Search
    }
  ]
})
import Vue from 'vue'
import Router from 'vue-router'
import Reacommed from 'components/reacommed/reacommed'
import Search from 'components/search/search'
import Singer from 'components/singer/singer'
import Rank from 'components/rank/rank'
 
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/reacommed',
      component:Reacommed
    },
    {
        path:'/singer',
        component:Singer
    },
    {
        path:'/rank',
        component:Rank
    },
    {
        path:'/search',
        component:Search
    }
  ]
})
index。js

3:如何引入router实例

import 'babel-polyfill'
import Vue from 'vue'
import App from './App'
// 1这里的router是index。js的实例
import router from './router'
import fastclick from 'fastclick'

import 'common/stylus/index.styl'


Vue.config.productionTip = false

// 取消点击300毫秒的延迟
fastclick.attach(document.body) 

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 2
  router,
  components: { App },
  template: ''
})
main.js

注册url

import Vue from 'vue'
import Router from 'vue-router'
import Recommend from 'components/recommend/recommend'
import Search from 'components/search/search'
import Singer from 'components/singer/singer'
import Rank from 'components/rank/rank'
 
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/recommend',
      component:Recommend
    },
    {
        path:'/singer',
        component:Singer
    },
    {
        path:'/rank',
        component:Rank
    },
    {
        path:'/search',
        component:Search
    }
  ]
})
index.js

4:显示在App.vue页面

知识点:

router-linnk

a:里面有一个tag属性,控制其显示的为什么标签

如:tag=“a”,即显示为a标签

b:router-link-active

当前某个router-link被激活的时候,会添加样式

5:将导航条添加进去

a:先在app.vue导入进去tab组件

b:注册

c:渲染





app.vue

url重定向

redirect

三:在app.vue导入组件

    import MHeader from './components/m-header/m-header'
    import Tab from './components/tab/tab'

首字母要大写,因为其本质上是class,class书写规范为首字母大写


 

jsonp

jsonp(url, opts, fn)
 url (String) url to fetch
 opts (Object), optional
    param : 指定回调函数名
    timeout : 超时时间,默认一分钟
    prefix : __jp 默认添加前缀
    name
fn callback (回调函数)

四:抓取qq音乐的数据

XHR:ajax请求

1:可以自己手写

2:引用插件

下载安装jsonp

npm install jsonp

.jsonp是什么?jsonp是目前可以跨域的(基本上标签带有src属性的都是可以不受任何访问限制),且要动态生成script标签在ajax无法跨域的情况下可以使用jsonp进行请求但它跟ajax是不一样的..jsonp利用url链接进行请求发送和调用回调函数(callblack)使用数据。

1:封装一个jsonp方法

用于拼接url
import originJsonp from 'jsonp' // 引用 export default function jsonp(url, data, option) {
  // 将url和data对象进行拼接成url拼接 url
+= (url.indexOf('?') < 0 ? '?' : '&') + param(data) // param 是一个拼接函数将data专门转化成url形式
  
  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) : '' }

 Promise对象有2个参数(resolve,reject)

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),
在异步操作成功时调用,并将异步操作的结果,作为参数传递出去; reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),
在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise()充当异步操作和回调函数的中介,起到代理的作用

param()data数据对象转化成url格式

function param(data){
    let url = '';
     //遍历拼接对象
    for(var k in data){
      //以&a=123=yu=789 这样形式拼接
      let value = data[k] !== undefined ?data[k] : '';
      url += `&${k}=${encodeURIComponent(value)}`;        //es6语法
    }
    return url ? url.substring(1):'';
}

在创建的config.js下写入jsonp请求通用公共参数

xport const commonParams = {
    g_tk: 5381,
    inCharset: 'utf-8',
    outCharset: 'utf-8',
    notice: 0,
    format: 'jsonp',
}
// 设置常量 param export
const options = { param: 'jsonpCallback' }
// 设置常量 错误信息 0 是 ok export
const ERR_OK = 0

recommend.js文件下写入抓取QQ音乐轮播图需要发送数据

import jsonp from '../common/js/jsonp' //引入自定义封装的jsonp函数
import { commonParams, options } from './config'
export function getRecommend() {
    //轮播图请求地址
   const url = 'https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg'; 
    利用es6对象方法进行浅拷贝将数组对象合并到第一个{}对象中
    const data = Object.assign({}, commonParams, {
        platform: 'h5',
        uin: 0,
        needNewCode: 1
    })
    //调用jsonp方法 进行url拼接
    return jsonp(url, data, options)
}

.组件页面得到数据

将其js文件引入组件中

import {getRecommend} from 'api/recommend';
import {ERR_OK} from 'api/config'g'

获取数据

  _getRecommend(){
          //因为return new Promise中有.then表示如果异步成功完成就执行
        getRecommend().then(res=>{
          if(res.code === ERR_OK){
             console.log(res.data.slider)
             this.recommend = res.data.slider;        
//放入组件data中接着传入到轮播组件中使用v-for渲染 } }) }

 

 

vue music-抓取歌单列表数据(渲染轮播图)_第2张图片

编写拼接url的方法(getRecommend)

MusicJsonCallback30832226944503405({"code":0,
"subcode":0,"msg":"",
"data":{"total":4,"items":[{"from":2,"status":0,"msg_num":0},
{"from":4,"status":0,"msg_num":0},{"from":5,"status":0,"msg_num":0},
{"from":6,"status":0,"msg_num":0}]}})

 

从recommend调用getRecommend方法

推荐页面

recommend。vue

_getRecommend() {
     getRecommend().then((res) => {
           if(res.code === ERR_OK){
               // 轮播图数据
            this.recommends = res.data.slider
       }
     })
},


 

手写轮播图组件 base/slider

better-scroll文档**

slider.vue






slider。vue
class="slider" ref="slider">---> 最外层容器
class="slider-group" ref="sliderGroup">---> 内层容器 sliderGroup轮播图,只能设置宽度,高度固定 1:获取整个列表有多少个元素 this.children = this.$refs.sliderGroup.children 2:父元素的宽度,图片撑开的宽度 let sliderWidth = this.$refs.slider.clientWidth

 给轮播图图片添加样式

(手动写的class,耦合性太强)

a、dom。js--->只对dom元素进行操作的方法(通用)

vue music-抓取歌单列表数据(渲染轮播图)_第3张图片

b、再导入dom。js

    // 对dom元素操作的组件
    import {addClass} from 'common/js/dom'

c、将slider-item样式添加进去

addClass(child,'slider-item')


计算部分
// 子容器的宽度 要等于父容器的宽度 需要添加单位'px'
child.style.width = sliderWidth + 'px'
// 总宽度需要+父容器的宽度
width += sliderWidth

loop:{
       // 循环轮播
      type:Boolean,
      default: true
},

// 保证其能进行循环切换,需克隆2个sliderWidth-->即宽度需要加2倍sliderWidth
if(this.loop && !isResize){
     width += 2 * sliderWidth
}

最后设置宽度
this.$refs.sliderGroup.style.width = width + 'px'

问题:当后面方法需要获取数据时,而获取数据的方法还未执行完毕

在recommend。vue进行判断数据长度
if='recommends.length' class="slider-wrapper">
for="item in recommends"> "item.linkUrl"> "item.picUrl">

 

recommend.vue推荐页面






推荐页面

轮播图下的圆圈






slider.vue

将轮播图当前页与小圆圈绑定样式

 
class="dots">
class="dot" v-for = '(item,index) in dots' :class="{active: currentPageIndex === index}">
  

index--->索引当前第几个元素

添加样式active

 :class="{active: currentPageIndex === index}">
currentPageIndex:标识当前页数  
需要先在data() 方法里面初始化currentPageIndex

export default{ data(){ return { dots:[], // 标识当前页数 currentPageIndex: 0 } },

到索引的页面就添加active类

vue music-抓取歌单列表数据(渲染轮播图)_第4张图片

当前对象。也就是指.dot

当dot是active的时候,就添加样式

维护currentPageIndex

currentPageIndex什么时候切换的?如何将滚动到的页面与currentPageIndex结合?
 
当初始化slider的时候,绑定事件

 // 当滚动到下一张会触发scrollEnd事件
scrollEnd事件会派发一个回调函数
 this.slider.on('scrollEnd', ()=>{
    // 获取当前 getCurrentPage()为slider的方法  返回的对象有个pageX方法
pageX--->当前第几个元素
         let pageIndex = this.slider.getCurrentPage().pageX
           if (this.loop) {
                 pageIndex -= 1
                        //再循环模式下,会默认在第一个元素添加一个拷贝 所以要减1
                    }
           this.currentPageIndex = pageIndex
 })
 
     
这里我们用到了 Vue 的特殊元素—— slot 插槽,它可以满足我们灵活定制列表 DOM 结构的需求。接下来我们来看看 JS 部分:
 
     
JS 部分实际上就是对 better-scroll 做一层 Vue 的封装,通过 props 的形式,
把一些对 better-scroll 定制化的控制权交给父组件;
通过 methods 暴露的一些方法对 better-scroll 的方法做一层代理;
通过 watch 传入的 data,当 data 发生改变的时候,
在适当的时机调用 refresh 方法重新计算 better-scroll 确保滚动效果正常,
这里之所以要有一个 refreshDelay 的设置是考虑到如果我们对列表操作用到了 transition-group 做动画效果
,那么 DOM 的渲染完毕时间就是在动画完成之后。 有了这一层 scroll 组件的封装,我们来修改刚刚最复杂的代码(假设我们已经全局注册了 scroll 组件)。
可以很明显的看到我们的 JS 部分精简了非常多的代码,没有对 better-scroll 再做命令式的操作了,
同时把数据请求和 better-scroll 也做了剥离,父组件只需要把数据 data 通过 prop 传给 scroll 组件,
就可以保证 scroll 组件的滚动效果。
同时,如果想实现下拉刷新的功能,只需要通过 prop 把 pulldown 设置为 true
并且监听 pulldown 的事件去做一些数据获取并更新的动作即可,整个逻辑也是非常清晰的。

 

动态的给子元素设置宽度,当能滑动或者自动轮播的时候,子元素的宽度乘以2,用来切换,因为轮播图想无缝滑动,
必须将第一张图放到最后一个位置,最后一张图放到第一张的位置前面,假如有五个轮播图的话,
事实上,获取的宽度是七张图的宽度。

自动播放

slider.vue

 props:{
     loop:{
      // 循环轮播
      type:Boolean,
     default: true
  },
 autoPlay:{
       // 自动轮播
      ype:Boolean,
      default: true

优化:

当屏幕宽度变化的时候,图片错位,而宽度是由sliderWidth控制的

方法: 监听Windows的resizer事件,重新渲染sliderWidth

        //监听窗口改变事件
        window.addEventListener('resize', () => {
            if (!this.slider){
        // 初始化的时候直接返回
return } // 重新调用计算宽度的方法 this._setSliderWidth(true) }) },
 
     

window窗口改变事件:resize

addEventListener() 方法

用于向指定元素添加事件句柄

element.addEventListener(event, function, useCapture)

参数:
event:
必须。字符串,指定事件名。

注意: 不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"


function
必须。指定要事件触发时执行的函数。

当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如,
 "click" 事件属于 MouseEvent(鼠标事件) 对象。


useCapture
可选。布尔值,指定事件是否在捕获或冒泡阶段执行。

可能值:

    true - 事件句柄在捕获阶段执行
    false- false- 默认。事件句柄在冒泡阶段执行
参数

添加标志位,重置过的设置为true

        methods:{
        // isResize标志位判读是不是重置过来的 _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 }
          // && !isResize
if(this.loop && !isResize){
          // 刚开始进来只需要加一次宽度 width
+= 2 * sliderWidth } this.$refs.sliderGroup.style.width = width + 'px' },

 

 

 

 
     

知识点

1:slot---> 插槽

2:使用better-scroll

3:created和mounted

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
其实两者比较好理解,通常created使用的次数多,而mounted通常是在一些插件的使用或者组件的使用中进行操作,比如插件chart.js的使用: var ctx = document.getElementById(ID);通常会有这一步,而如果你写入组件中,你会发现在created中无法对chart进行一些初始化配置,一定要等这个html渲染完后才可以进行,那么mounted就是不二之选。下面看一个例子(用组件)。

 

 

 

转载于:https://www.cnblogs.com/jassin-du/p/9431789.html

你可能感兴趣的:(vue music-抓取歌单列表数据(渲染轮播图))