1. 程式人生 > >vue2學習仿qq音樂的心路歷程

vue2學習仿qq音樂的心路歷程

隨著網際網路的高速發展,技術不斷的更新迭代,web這一領域技術發展更是快的不行,幾年前風靡全球的jQuery,現在看來也遇到了瓶頸,現在web更是講究框架模組化開發,react/vue/angular等框架就是這web發展所需的時代產物,好了,感慨就到這裡吧。。。。。。第一次發博,算是學習之路的一個記錄

 

1.這裡主要記錄一下qq音樂介面變化的問題,之前qq音樂歌曲地址是不需要vkey這樣的引數的,視訊上講的只能指引你,真要掌握、吃透還得靠自己去不斷查詢,不斷髮現。所以說,朋友們,發現自己不懂的問題,才是最重要的。


這裡貼出視訊裡suggest.vue的程式碼

searchMore() {
        if (!this.hasMore) {
          return
        }
        this.page++
        search(this.query, this.page, this.showSinger, perpage).then((res) => {
          if (res.code === ERR_OK) {
            this.result = this.result.concat(this._genResult(res.data))
            this._checkMore(res.data)
          }
        })
      }
_genResult(data) {
        let ret = []
        if (data.zhida && data.zhida.singerid) {
          ret.push({...data.zhida, ...{type: TYPE_SINGER}})
        }
        if (data.song) {
          ret = ret.concat(this._normalizeSongs(data.song.list))
        }
        return ret
      }
_normalizeSongs(list) {
        let ret = []
        list.forEach((musicData) => {
          if (musicData.songid && musicData.albummid) {
            ret.push(createSong(musicData))
          }
        })
        return ret
      }

然後是qq音樂介面變化後(需要vkey等引數),缺什麼,我們就去找什麼

1.首先到api/singer.js下加一個獲取vkey的方法

export function getSongVkey (songmid) { // 獲取歌曲的vkey
    const url = '/getVkey'

    const data = Object.assign({}, commonParams, {
        callback: 'get002341',
        jsonpCallback: 'get002341',
        loginUin: 0,
        hostUin: 0,
        format: 'jsonp',
        platform: 'yqq',
        needNewCode: 0,
        data: `{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"5416664912","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"5416664912","songmid":["${songmid}"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":20,"cv":0}}`
    })

    return axios.get(url,{
        params:data
    }).then((res) => {
        return Promise.resolve(res.data)
    }).catch((e) => {
        console.log(e)
    })
}

2.然後到webpack.dev.conf.js中去設定代理請求資料

app.get('/getVkey', function (req, res) {//這裡的路徑是給前端傳送請求的url
            const url = 'https://u.y.qq.com/cgi-bin/musicu.fcg'
            // axios傳送get請求,可以自己配置config
            axios.get(url, {
                headers: {
                    referer: 'https://y.qq.com/',
                    host: 'u.y.qq.com'
                },
                //  params是即將與請求一起傳送的url引數,無格式物件/URLSearchParams物件
                params: req.query
            }).then((response) => {
                let rest = response.data
                if(typeof rest === 'string') {
                    let reg = /^\w+\(({[^()]+})\)$/
                    let matches = rest.match(reg)
                    if(matches) {
                        rest = JSON.parse(matches[1])
                    }
                }
                res.json(rest)
            }).catch((e) => {
                console.log(e)
            })
        })

這裡是我們需要的url

 以及需要的引數欄位及內容

 重點是域名後面的引數,不要太刻意關注域名,這是音樂檔案的真實地址

 common/js/song.js  createSong方法引數內容變化

export function createSong(musicData, filename, vkey) {
    return new Song({
        id: musicData.songid,
        mid: musicData.songmid,
        singer: filterSinger(musicData.singer),
        name: musicData.songname,
        album: musicData.albumname,
        duration: musicData.interval,
        image: `https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000`,
        url: `http://dl.stream.qqmusic.qq.com/${filename}?guid=5416664912&vkey=${vkey}&uin=0&fromtag=66`
    })
}

2.最後是自己不斷的摸索,不斷的查詢,然後到思否上提問,才找到解決問題的關鍵所在

先貼出自己suggest.vue的三個函式變化

_normalizeSongs(list, callback) {
            if(!list) {
                return
            }
            let rest = []
            let index = 1
            list.forEach((musicData) => {
                if(musicData.songid && musicData.albummid) {
                    let promise = getSongVkey(musicData.songmid) //獲取歌曲filename及vkey
                    promise.then((res) => {
                        if(res.code === ERR_OK) {
                            const filename = res.req_0.data.midurlinfo[0].filename
                            const vkey = res.req_0.data.midurlinfo[0].vkey
                            const newSong = createSong(musicData, filename, vkey)
                            // console.log(newSong)
                            rest.push(newSong)  //將獲取到的歌曲加入到陣列中
                            if(index === list.length) {
                                callback && callback(rest)
                            }
                            index++
                        }
                    })
                }
            })
        }
_genResult(data, callback) {
            let rest = []
            if(data.zhida && data.zhida.singername) {
                rest.push({...data.zhida,...{type: TYPE_SINGER}})
            }
            if(data.song) {
                this._normalizeSongs(data.song.list, (restdata) => {
                    rest = rest.concat(restdata)
                    callback && callback(rest)
                })
            }
        }
search() {
            this.hasMore = true
            this.page = 1   //當query發生改變時,page重置為1
            this.$refs.suggest.scrollTo(0, 0)
            search(this.query, this.page, this.showSinger, Perpage).then((res) => {
                if(res.code === ERR_OK) {
                    this._genResult(res.data, (rest) => {
                        // console.log(rest)
                        this.result = rest
                    })
                    this._checkMore(res.data)
                }
            })
        }

其中searchMore方法也有小小變化

searchMore() {
            if(!this.hasMore) {
                return
            }
            this.page++
            search(this.query, this.page, this.showSinger, Perpage).then((res) => {
                if(res.code === ERR_OK) {
                    this._genResult(res.data, (rest) => {
                        this.result = this.result.concat(rest) //把新搜尋到的資料拼接到之前搜尋到的資料中
                    })
                    this._checkMore(res.data)
                }
            })
        }

!!!重點來了,要考的

對比之後會發現,視訊裡的_normalizeSongs方法和_genResult方法會有一個return的值,我的問題就在這裡,因為qq音樂介面引數變化後,需要用到getSongVkey這個方法,這個方法返回的是promise物件,然而我要在迴圈裡執行這個非同步方法,沒辦法在迴圈外return想要的結果,最後在思否上提問,得到道友的解惑,通過callback這個引數得到我想要的return,在promise.then()中call&&callback(rest),自己想要的結果就會被這個rest收留,然後在其他函式裡進行下一步操作,總結說來視訊裡的某個函式return的結果也是被另外的函式當做引數來進行下一步操作,方法不同,思路不同,得到的結果卻是相同的,關鍵是怎麼去看待問題,才能採取相應的方法去應對;思否提問地址https://segmentfault.com/q/1010000016912296,感興趣的可以去看看,漫漫學習路,記一筆。。。