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,感興趣的可以去看看,漫漫學習路,記一筆。。。