• 【音乐App】—— Vue-music 项目学习笔记:歌单及排行榜开发


    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记。

    项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star。


    歌单及详情页 排行榜及详情页
    一、歌单详情页开发

           歌单详情页布局介绍及Vuex实现路由数据通讯

    • components->disc目录下:创建disc.vue
    • router->index.js中:给Recommend添加二级子路由Disc
      {
          path: '/recommend',
          component: Recommend,
          children: [
              {
                  path: ':id',
                  component: Disc
              }
          ]
      }
    • recommend.vue中:
    1. 添加路由容器
      <router-view></router-view>
    2. 给歌单列表添加点击事件
      @click="selectItem(item)"
    3. 定义selectItem()实现路由跳转
      selectItem(item) {
          this.$router.push({
              path: `/recommend/${item.dissid}`
         })
      }
    • 使用vuex传递歌单数据
    1. state.js中:添加歌单对象
      disc: {}
    2. mutation-type.js中:定义type常量
      export const SET_DISC = 'SET_DISC'
    3. mutation.js中:创建更改函数
      [types.SET_DISC](state, disc){
          state.disc = disc
      }
    4. getters.js中:定义数据映射
      export const disc = state => state.disc
    • recommend.vue中:使用mapMutations修改disc
      import {mapMutations} from 'vuex'
      
      ...mapMutations({
          setDisc: 'SET_DISC'
      })
      
      selectItem(item) {
          this.$router.push({
               path: `/recommend/${item.dissid}`
          })
         this.setDisc(item) //更改state中的disc
      }
    • disc.vue中:通过mapGetters获取到date中的disc
      import {mapGetters} from 'vuex
      
      computed: {
         ...mapGetters([
               'disc'
         ])
      }
    • 传递数据:获取数据在computed里面,设置数据在methods里面

           歌单详情页数据抓取

    • api->recommend.js中:添加getSonglist接口
      export function getSongList (disstid) {
           const url = '/api/getSongList'
      
           const data = Object.assign({}, commonParams, {
               uin: 0,
               format: 'json',
               notice: 0,
               needNewCode: 1,
               new_format: 1,
               pic: 500,
               disstid, //关键数据
               type: 1,
               json: 1,
               utf8: 1,
               onlysong: 0,
               picmid: 1,
               nosign: 1,
               song_begin: 0,
               platform: 'h5',
               song_num: 100,
               _: +new Date()
          })
      
          return axios.get(url, {
               params: data
          }).then((res) => {
               return Promise.resolve(res.data)
          })
      }
    • 因为数据也经过加密,在webpack.dev.config.js中模仿header:
      app.get('/api/getSongList', function (req, res) {
           var url = 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg'
           axios.get(url, {
                 headers: {
                      referer: 'https://y.qq.com/',
                      host: 'c.y.qq.com'
                 },
                 params: req.query
          }).then((response) => {
                 res.json(response.data)
          }).catch((e) => {
                 console.log(e)
          })
      })

      注意:后端配置之后,一定要重新启动!!!

           歌单详情页数据的处理和应用

    • 调用getSongList()方法获取数据,在created()时获取
      import {getSongList} from '@/api/recommend'
      
      _getSongList () {
           if(!this.disc.dissid){ //在歌单详情页强制刷新后,即没有获得id时,回退到推荐页面
               this.$router.push('/recommend')
               return
           }
           getSongList(this.disc.dissid).then((res) => {
               if (res.code === ERR_OK) {
                   this.songs = this._normalizeSongs((res.cdlist[0].songlist))
                    // console.log(res)
                    // console.log(res.cdlist[0].songlist)
                    // console.log(this._normalizeSongs(res.cdlist[0].songlist))
               }
          })
      }
    • 获得数据后,在methods中对数据进行一些处理
    1. 同歌手详情页,歌曲的播放url中的vkey需要发送请求获取,同时将处理好的数据封装新的Song实例
      import {ERR_OK} from '@/api/config'
      import {creatSongList} from '@/common/js/song'
      import {getMusic} from '@/api/singer'
      
      _normalizeSongs (list) {
          let ret = []
          list.forEach((musicData) => {
               if (musicData.id && musicData.album) {
                      // ret.push(creatSongList(musicData))
                      getMusic(musicData.mid).then((res) => {
                             // console.log(res)
                             if(res.code === ERR_OK){
                                  // console.log(res.data)
                                  const svkey = res.data.items
                                  const songVkey = svkey[0].vkey
                                  const newSong = creatSongList(musicData, songVkey)
                                   ret.push(newSong)
                             }
                      })
               }
          })
          return ret
      }

      其中:调用getMusic()获取播放地址的vkey,调用creatSongList()实例化Song对象

    2. common->js->song.js中: 创建creatSongList()
      export function creatSongList (musicData, songVkey) {
                return new Song({
                       id: musicData.id,
                       mid: musicData.mid,
                       singer: filterSinger(musicData.singer),
                       name: musicData.name,
                       album: musicData.albumname,
                       duration: musicData.interval,
                       image: `https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.album.mid}.jpg?max_age=2592000`,
                       //注意guid以实时数据为主
                       url: `http://ws.stream.qqmusic.qq.com/C400${musicData.mid}.m4a?vkey=${songVkey}&guid=6319873028&uin=0&fromtag=66`
               })
      }
    二、排行榜及详情页开发

           排行榜数据抓取

    • 在api目录下:创建rank.js添加获取数据的接口
      import jsonp from '@/common/js/jsonp'
      import {commonParams, options} from './config'
      
      export function getTopList() {
           const url = "https://c.y.qq.com/v8/fcg-bin/fcg_myqq_toplist.fcg"
      
           const data = Object.assign({}, commonParams, {
                    platform: 'h5',
                    needNewcode: 1
           })
      
           return jsonp(url, data, options)
      }
    • rank.vue中:调用getTopList()方法获取数据,在created()时获取
      import {getTopList} from '@/api/rank'
      import {ERR_OK} from '@/api/config'
      
      created() {
          this._getTopList()
      },
      methods: {
          _getTopList() {
                getTopList().then((res) => {
                      if(res.code === ERR_OK){
                             console.log(res.data.topList)
                      }
                })
          }
      }

           排行榜数据应用

    • 在data中维护数据
      topList: []
    • 获取数据后赋值
      this.topList = res.data.topList
    • 将数据填入DOM:应用scroll组件替换父元素<div>并传入topList数据实现滚动
      <scroll class="top-list" :data="topList">
    • 优化:应用loading组件,设置当topList没有内容时显示loading
    • 优化:应用mixin,实现播放器底部适配

           榜单详情页布局及Vuex实现路由数据通讯

    • 路由的跳转
    1. router->index.js中:设置Rank的二级路由
      import TopList from '@/components/top-list/top-list' 
      
      {
          path: '/rank',
          component: Rank,
          children: [
              {
                    path: ':id',
                    component: TopList
               }
          ]
      }
    2. rank.vue中:添加路由容器,给列表添加点击事件,触发路由的跳转

      <router-view></router-view>
      @click="selectItem(item)"
      selectItem(item) {
          this.$router.push({
               path: `/rank/${item.id}`
          })
      }
    • Vuex传递数据
    1. state.js中:定义数据
      topList: {}
    2. mutation-types.js中:定义type常量
      export const SET_TOP_LIST = 'SET_TOP_LIST'
    3. mutations.js中:添加修改topList的方法
      [types.SET_TOP_LIST](state, topList){
           state.topList = topList
      }
    4. getters.js中:添加topList的数据映射
      export const topList = state => state.topList
    • 写入和获取state数据
    1. rank.vue中:通过mapMutations写入数据
      import {mapMutations} from 'vuex'
      
      this.setTopList(item)
      
      ...mapMutations({
          setTopList: 'SET_TOP_LIST'
      })
    2. top-list.vue中:通过mapGatters拿到数据
      import {mapGetters} from 'vuex'
      
      computed: {
          ...mapGetters([
              'topList'
         ])
      }

      剩下的就是获取数据用computed,设置数据用methods

           榜单详情歌曲数据的抓取

    • 需求:榜单本身的背景图不好看,想要抓取榜单详情歌曲的图片作为背景图
    • 问题:原请求是Ajax请求,不能跨域,但也支持jsonp请求,只是没有格式化不方便查看数据
    • 解决: 在线网站www.bejson.com 格式化为json文件
    • 因为这块数据QQ音乐也做了加密,这里抓取数据同歌单详情页方式
    1. api->rank.js中:添加获取数据的接口
      export function getMusicList(topid) {
           const url = "https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg"
      
           const data = Object.assign({}, commonParams, {
                    page: 'detail',
                    type: 'top',
                    tpl: 3,
                    platform: 'h5',
                    needNewcode: 1
           })
      
           return jsonp(url, data, options)
      }
    2. top-list.vue中:调用getMusicList()方法获取数据,在created()时获取
      import {getMusicList} from '@/api/rank'
      import {ERR_OK} from '@/api/config'
      
      created() {
          this._getMusicList()
      }
      
      getMusicList(this.topList.id).then((res) => {
          if(res.code === ERR_OK){
             this.songs = this._normalizeSongs(res.songlist)
             // console.log(res.songlist)
          }
      })
    3. 获得数据后,在methods中对数据进行一些处理:同歌单详情页,歌曲的播放url中的vkey需要发送请求获取,同时将处理好的数据封装新的Song实例
      import {getMusic} from '@/api/singer'
      import {createSong} from '@/common/js/song'
      
      _normalizeSongs(list) {
            let ret = []
            list.forEach((item) => {
                  const musicData = item.data
                  // console.log(musicData)
                  if (musicData.songid && musicData.albumid) {
                      getMusic(musicData.songmid).then((res) => {
                             // console.log(res)
                             if(res.code === ERR_OK){
                                 // console.log(res.data)
                                 const svkey = res.data.items
                                 const songVkey = svkey[0].vkey
                                 const newSong = createSong(musicData, songVkey)
                                 ret.push(newSong)
                             }
                     })
                 }
           })
           return ret
      }

      这样数据就获取到了,剩下的把songs的数据传递给子组件就可以了

    • 把bgImage的图片换成榜单第一首歌的图片
      bgImage() {
         if (this.songs.length) {
             return this.songs[0].image
         }
         return this.topList.picUrl
      }

           带排行的song-list组件的扩展和应用

    • 添加rank的DOM结构、图片以及样式
    • 添加props字段rank,默认false,设置只有当rank为true时排行显示
      rank: {
          type: Boolean,
          default: false
      }
      <div class="rank" v-show="rank">
    • 定义两个方法分别获得动态绑定的class和文案
      <span :class="getRankCls(index)">{{getRankText(index)}}</span>
      getRankCls(index) {
           if(index<=2) {
               return `icon icon${index}`
           }else{
               return 'text'
          }
      },
      getRankText(index) {
          if(index > 2) {
               return index + 1
          }
      }
    • music-list.vue作为中间组件,也需要扩展一个props字段rank
      rank: {
           type: Boolean,
           default: false
      }
    1. 传入<song-list>
      <song-list :rank="rank"></song-list>
    2. 这样就把最外层父组件传入的rank应用到了song-list.vue组件中
    3. top-list.vue中维护数据rank为true,同时传入<music-list>中

     注:项目来自慕课网

  • 相关阅读:
    Discuz X 2.5 点点(伪静态)
    jq 、xml 省市级联动
    php memcache 初级使用(2)
    关于windows虚拟内存管理的页目录自映射
    SharePoint 2010 网络上的开发经验和资源
    SharePoint 2010 Reporting Services 报表服务器正在内置 NT AUTHORITY\SYSTEM 账户下运行 解决方法
    SharePoint 2010 Reporting Services 报表服务器无法解密用于访问报表服务器数据库中的敏感数据或加密数据的对称密钥 解决方法
    Active Directory Rights Management Services (AD RMS)无法检索证书层次结构。 解决方法
    SharePoint 2010 Reporting Services 报表服务器实例没有正确配置 解决方法
    SharePoint 2010 页面引用 Reporting Services 展现 List 报表
  • 原文地址:https://www.cnblogs.com/ljq66/p/10168769.html
Copyright © 2020-2023  润新知