1. 首先,获取歌单推荐部分的数据,与获取推荐数据不同,热门歌单数据的接口有host和referer的显示,我们的api请求被拒绝(500错误),必须要修改header,但是前端不能直接修改request header,我们采取后端接口代理的方法去解决。使用express,不是直接请求服务器的url,而是请求我们自己的server端,让local server再去请求QQ服务端

使用express启动代理服务器,原理:在getDiscList中不是直接请求url,而是请求express服务器端地址,再让我们的地址去请求服务端,使用nodejs请求服务器端,用到一个axios库,在浏览器端发送的是xmlhttprequest请求,在nodejs中发送的是http请求

我们使用axios请求服务器,在webpack-dev-conf.js中做如下配置

const express = require('express')
const axios = require('axios')
const app = express()
var apiRoutes = express.Router()
app.use('/api', apiRoutes)

在devServer{}中添加

before(app) {app.get('/api/getDiscList', (req, res) => {var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'axios.get(url, {headers: {referer: 'https://c.y.qq.com/',host: 'c.y.qq.com'},params: req.query // 通过req从浏览器端发过来的一堆参数(platform,sin,ein等)透传给qq的服务端}).then((response)=>{ // qq服务端的响应数据,再通过res将响应数据输出到浏览器端res.json(response.data)}).catch((error)=>{console.log(error)})})}

之后,回到recommend.js中获取数据,请求的是本地express服务器的api数据(ajax请求),(本地express的数据是上边通过axios获得的)不是Jsonp数据了,返回的是axios的数据

import axios from 'axios'
export function getDiscList() {const url = '/api/getDiscList'const data = Object.assign({}, commonParams, {platform: 'yqq',hostUin: 0,sin: 0,ein: 29,sortId: 5,needNewCode: 0,categoryId: 10000000,rnd: Math.random(),format: 'json' // 将format从jsonp修改为json})return axios.get(url, {params: data}).then((res) => {return Promise.resolve(res.data)})
}

2 将获取到的数据添加到DOM中,ul-li 并编写样式

import {getRecommend, getDiscList} from 'api/recommend'
import {ERR_OK} from 'api/config'

先定义歌单的原始数据,并将其绑定到data中

data() {return {recommends: [],discList: []}},
 created() {//  setTimeout(() => {//    this._getRecommend() //  }, 2000);this._getRecommend() // 模拟loading效果// setTimeout(() => {//  this._getDiscList()// }, 1000);this._getDiscList()},methods: {_getRecommend() {getRecommend().then((res) => { // res对应的就是json对象if (res.code === ERR_OK) {// console.log(res.data.slider)this.recommends = res.data.slider // 根据fcp数据的格式返回的}})},_getDiscList() {getDiscList().then((res) => {if (res.code === ERR_OK) {// console.log(res.data.list)this.discList = res.data.list}})}

填充DOM

        <div class="recommend-list"><h1 class="list-title">热门歌单推荐</h1><ul><li v-for="item in discList" :key="item.id" class="item"><div class="icon"><img width="60" height="60" v-lazy="item.imgurl"></div><div class="text"><h2 class="name" v-html="item.creator.name"></h2><p class="desc" v-html="item.dissname"></p></div></li></ul></div>

3. 榜单优化:局部滚动,但是顶部不滚动,因为考虑到BScroll的复用性很大,我们将其抽象成一个组件,暂时初始化这些,如果有需要会在添加,在base下添加sroll组件

 <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},data: {type: Array, // refresh 数据default: null},listenScroll: { // 要不要监听滚动事件type: Boolean,default: false}},mounted() { // 确保DOM被渲染setTimeout(() => {this._initScroll()}, 20)},methods: {_initScroll() {if (!this.$refs.wrapper) { // wrapper没有值的时候,直接returnreturn}this.scroll = new BScroll(this.$refs.wrapper, {probeType: this.probeType,click: this.click})// 如果要监听滚动事件,在初始化列BScroll之后要派发一个监听事件if (this.listenScroll) {// BScroll 中的this是默认指向scroll的,所以要在me中保留vue实例的thislet me = this// 监听scroll,拿到pos后,派发一个函数将pos传出去this.scroll.on('scroll', (pos) => {me.$emit('scroll', pos)})      }},enable() { // 代理方法,将scroll原生的方法都添加到我们生成的this.scroll实例上this.scroll && this.scroll.enable()},disable() {this.scroll && this.scroll.disable()},refresh() {this.scroll && this.scroll.refresh()},scrollTo() {this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments) // applay引用到上下文中},scrollToElement() {this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)}},// 要随时watch data变化时进行刷新watch: {data() {setTimeout(() => {this.refresh()}, 20)}}}
</script><style scoped lang="stylus" rel="stylesheet/stylus"></style>

4. 回到recommend.vue组件,注册并引入组件,在DOM中,我们为其添加一个内层元素div,一般在外层元素(<div class="recommend-content">)上引用ref,然后在内外层组件之间添加scroll组件,不要忘记将data传到组件中,这样data值发生变化的时候就会自动刷新了

  <div class="recommend"><scroll ref="scroll" class="recommend-content" :data="discList"><div><div v-if="recommends.length" class="silder-wrapper"><slider><div v-for="item in recommends" :key="item.id"><a :href="item.linkUrl"><img :src="item.picUrl" class="needsclick" @load="loadImage"></a></div></slider></div><div class="recommend-list"><h1 class="list-title">热门歌单推荐</h1><ul><li v-for="item in discList" :key="item.id" class="item"><div class="icon"><img width="60" height="60" v-lazy="item.imgurl"></div><div class="text"><h2 class="name" v-html="item.creator.name"></h2><p class="desc" v-html="item.dissname"></p></div></li></ul></div></div><div class="loading-container" v-show="!discList.length"><loading></loading></div></scroll></div>

但是此时页面并没有滚动,mounted去初始化内容的时候页面还没有渲染,DOM被撑开时候要重新计算BScroll并refresh,才可以将BScroll正确的滚动,所以将data传入,watch观测到数据的变化,去refresh BScroll

recommend.vue中

<scroll ref="scroll" class="recommend-content" :data="discList">

在scroll.vue中,观测到data变化就去刷新bscroll

 // 要随时watch data的变化watch: {data() {setTimeout(() => {this.refresh()}, 20)}}

5.recommend获取的过程是一个异步过程,图片的加载也是一个异步的过程,无法正确的获取到高度

slider(轮播图)的高度不知何时会被撑开,是没有考虑到的,所以对img进行监听,若是加载到图片,就调用scroll.vue的refresh()方法刷新,重新计算高度,这样即使slider晚两分钟加载,也不会造成BScroll的出错,因为图片加载到之后就会重新计算属性

 <img :src="item.picUrl" class="needsclick" @load="loadImage">
    loadImage() {if (!this.checkloaded) { // 一旦有一张图片撑开了高度,slider的高度就会被撑开this.$refs.scroll.refresh() // 调用scroll的refresh方法this.checkloaded = true // 确保逻辑只执行一次,因为只要有一张图片加载完成就会撑开高度}}

6. 为节省资源,才用图片懒加载,使用VueLazyload插件,npm安装之后,在main.js中注册,提供一张默认的图片

import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {loading: require('common/image/default.png')
})

在recommend.vue中,将:src="imgUrl" 换成 v-lazy ="imgUrl"

<img width="60" height="60" v-lazy="item.imgurl">

在轮播图的图片显示部分添加needsclick,使图片可以被点击

<img :src="item.picUrl" class="needsclick" @load="loadImage">

7. 开发loading组件

<template><div class="loading"><img width="24" height="24" src="./loading.gif"><p class="desc">{{title}}</p></div>
</template>
<script type="text/ecmascript-6">export default {props: {title: {type: String,default: '正在载入...'}}}
</script>
<style scoped lang="stylus" rel="stylesheet/stylus">@import "~common/stylus/variable".loadingwidth: 100%text-align: center.descline-height: 20pxfont-size: $font-size-smallcolor: $color-text-l
</style>

在recommend.vue中引用loading.vue,歌单没有数据时会出现loading

      <div class="loading-container" v-show="!discList.length"><loading></loading></div>
.loading-containerposition: absolutewidth: 100%top: 50%transform: translateY(-50%)

vue 移动端音乐(3) amp;amp;gt;热门歌单推荐部分(webpack-dev-conf.js做后端接口代理+scroll插件)相关推荐

  1. Vue运行报错webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

    vue 项目 npm run dev 运行时报错: npm ERR! xxx@1.0.0 dev: `webpack-dev-server --inline --progress --config b ...

  2. vue:hadoop@1.0.0 dev: `webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

    运行vue项目是报错: hadoop@1.0.0 dev: `webpack-dev-server --inline --progress --config build/webpack.dev.con ...

  3. vue项目运行不成功--@1.0.0 dev: **`webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

    项目场景: vue 新项目运行–安装依赖包–运行项目 问题描述: 安装依赖包不成功-运行不起来 //mobileap----mobileap是项目名称,package.josn里name(文件夹名称) ...

  4. Vue实现仿音乐播放器8-实现热门榜单效果

    效果 实现 热门榜单和今日推荐实现公用组件 1.今日推荐组件Today_Recommend.vue <h2>{{title}}</h2>写成动态标题 2.接受参数url等 pr ...

  5. vue - webpack.dev.conf.js

    描述:开发时的配置.(配置开发时的一些操作) 例如这里,是否自动打开浏览器(默认true) 1 'use strict' 2 3 // build/util.js 4 const utils = re ...

  6. Vue进阶(五十三):vue-cli 脚手架 webpack.prod.conf.js 配置文件详解

    文章目录 一.前言 二.optimize-css-assets-webpack-plugin 插件 三.拓展阅读 一.前言 webpack.prod.conf.js 配置文件是webpack生产环境核 ...

  7. vue移动端音乐---使用QQ音乐数据

    项目预览视频:https://www.bilibili.com/video/av76348323 项目github地址:https://github.com/8127yyq/vue-musicPlay ...

  8. 虾米音乐关停,QQ音乐、网易云上线虾米歌单迁移功能

    宋九九消息,阿里旗下平台虾米音乐发布公告称将关停虾米音乐,这个陪伴了我们12年的音乐平台就要走了,最后请在关停之前做好数据备份或导出.编辑宋九九 虾米音乐公告称: 将于2021年1月5日10点之前停止 ...

  9. 你们要的歌单:网易云音乐收藏量前100的歌单

    网易云音乐收藏量前100的歌单,这下不怕不够循环了, 纯音乐居多,国外音乐也多,特别小众的音乐还得靠自己发现. 温暖的假日下午,你手握咖啡看着书,听着轻音乐,多么惬意. 按照收藏量降序排序 90334 ...

最新文章

  1. iphone objective-c内存管理
  2. c++ 输出二进制_Python之输入输出(input_output)
  3. 技术分享 |《原神》部分渲染效果分析
  4. 七、功能性组件与事件逻辑(IVX 快速开发教程)
  5. 欧盟抢先发布人工智能道德准则:AI要以人为本,负责任且无偏见
  6. 仿path首页滑动效果
  7. 调用cryptography密码学API接口计算SHA256/SHA1哈希摘要
  8. Protobuf C++类中成员函数GetCachedSize()与ByteSize()的区别
  9. 微信打飞机java 源代码_微信打飞机
  10. 2019每特教育蚂蚁课堂-Java互联网微服务架构面试宝典v1
  11. 如何使用Python查找文本文件的Zipf分布
  12. 绘制计算机网络拓扑图,绘制网络拓扑图1.ppt
  13. java idea 免费_Java程序员看过来,IDEA 2020免费版本来了
  14. emd经验模态分解 matlab,经验模态分解(EMD)在地球物理资料中的应用(附MATLAB程序)...
  15. 深圳平安银行软件测试面试,中国平安银行面试笔试题目 软件测试方向
  16. 1987年,国际C语言混乱代码大赛
  17. 【树莓派基础小实验笔记】1. 点亮LED二极管
  18. 4g网络什么时候淘汰_5G时代来临后,4G真的会被淘汰吗,简单说一下
  19. java时钟代码_一个经典的JAVA APPLET时钟程序(一)
  20. 外行对程序员误会有多深!扎心了!

热门文章

  1. AWS SES发QQ邮箱拒收解决方案
  2. python发微信提醒天气_基于Python实现定时自动给微信好友发送天气预报
  3. Android中显示PDF的问题解决(安卓端使用pdf.js CDN模式)
  4. 【数字逻辑】学习笔记 第四章 Part2 常用组合逻辑电路与竞争、险象
  5. Tiled2Unity报错处理办法
  6. 深潜Kotlin协程(二十一):Flow 生命周期函数
  7. 【数据采集平台】教程-单页面采集
  8. 网络的形成-从原始部落到现代化世界
  9. 思科路由器、交换机的远程登录配置
  10. Rails博客软件 Enki