调用网易云Api接口实现移动Web网易云部分功能(搜索+列表+播放)
知識點自測
- 知道reset.css和flexible.js的作用
- 什么是組件庫-例如bootstrap作用
- yarn命令的使用
- 組件名字用name屬性方式注冊
- 如何自定義組件庫樣式
鋪墊(自學)
本地接口項目部署
下載網易云音樂node接口項目, 在本地啟動, 為我們vue項目提供數據支持
項目地址
備用地址
下載后, 安裝所有依賴, 在本地啟動起來, 測試訪問此地址是否有數據
http://localhost:3000, 看到如下頁面就成功了
> 總結: 前端請求本地的node項目, node服務器偽裝請求去拿網易云音樂服務器數據轉發回給自己前端
學習目標
1.1 網易云音樂-本地接口啟動
目的: 啟動本地網易云音樂API服務
1.2 網易云音樂-前端項目初始化
目標: 初始化項目, 下載必備包, 引入初始文件, 配置按需自動引入vant, 創建頁面組件
初始化工程
vue create music-demo下載需要的所有第三方依賴包
yarn add axios vant vue-router引入筆記代碼里準備好的reset.css和flexible.js - 實現樣式初始化和適配問題 - 引入到main.js
本次vant使用自動按需引入的方式
文檔: https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart
yarn add babel-plugin-import -D在babel.config.js - 添加插件配置
plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',style: true}, 'vant'] ]1.3 網易云音樂-需求分析
根據需求, 創建路由所需要的5個頁面的組件
Layout(布局, 頂部導航和底部導航) > 二級路由 Home 和 Search以及播放Play
創建需要的views下的頁面組件4個
views/Layout/index.vue - 負責布局(上下導航 - 中間二級路由切換首頁和搜索頁面)
/* 中間內容區域 - 容器樣式(留好上下導航所占位置) */ .main {padding-top: 46px;padding-bottom: 50px; }views/Home/index.vue - 標題和歌名樣式
/* 標題 */ .title {padding: 0.266667rem 0.24rem;margin: 0 0 0.24rem 0;background-color: #eee;color: #333;font-size: 15px; } /* 推薦歌單 - 歌名 */ .song_name {font-size: 0.346667rem;padding: 0 0.08rem;margin-bottom: 0.266667rem;word-break: break-all;text-overflow: ellipsis;display: -webkit-box; /** 對象作為伸縮盒子模型顯示 **/-webkit-box-orient: vertical; /** 設置或檢索伸縮盒對象的子元素的排列方式 **/-webkit-line-clamp: 2; /** 顯示的行數 **/overflow: hidden; /** 隱藏超出的內容 **/ }views/Search/index.vue
/* 搜索容器的樣式 */ .search_wrap {padding: 0.266667rem; }/*熱門搜索文字標題樣式 */ .hot_title {font-size: 0.32rem;color: #666; }/* 熱搜詞_容器 */ .hot_name_wrap {margin: 0.266667rem 0; }/* 熱搜詞_樣式 */ .hot_item {display: inline-blockheight: 0.853333rem;margin-right: 0.213333rem;margin-bottom: 0.213333rem;padding: 0 0.373333rem;font-size: 0.373333rem;line-height: 0.853333rem;color: #333;border-color: #d3d4da;border-radius: 0.853333rem;border: 1px solid #d3d4da; }Play頁面的index(可以全文復制)
<template><div class="play"><!-- 模糊背景(靠樣式設置), 固定定位 --><divclass="song-bg":style="`background-image: url(${songInfo && songInfo.al && songInfo.al.picUrl}?imageView&thumbnail=360y360&quality=75&tostatic=0);`"></div><!-- 播放頁頭部導航 --><div class="header"><van-iconname="arrow-left"size="20"class="left-incon"@click="$router.back()"/></div><!-- 留聲機 - 容器 --><div class="song-wrapper"><!-- 留聲機本身(靠css動畫做旋轉) --><divclass="song-turn ani":style="`animation-play-state:${playState ? 'running' : 'paused'}`"><div class="song-img"><!-- &&寫法是為了防止報錯, 有字段再繼續往下訪問屬性 --><imgstyle="width: 100%":src="`${songInfo && songInfo.al && songInfo.al.picUrl}?imageView&thumbnail=360y360&quality=75&tostatic=0`"alt=""/></div></div><!-- 播放按鈕 --><div class="start-box" @click="audioStart"><span class="song-start" v-show="!playState"></span></div><!-- 播放歌詞容器 --><div class="song-msg"><!-- 歌曲名 --><h2 class="m-song-h2"><span class="m-song-sname">{{ songInfo.name }}-{{songInfo && songInfo.ar && songInfo.ar[0].name}}</span></h2><!-- 歌詞部分-隨著時間切換展示一句歌詞 --><div class="lrcContent"><p class="lrc">{{ curLyric }}</p></div></div><!-- 留聲機 - 唱臂 --><div class="needle" :style="`transform: rotate(${needleDeg});`"></div></div><!-- 播放音樂真正的標簽看接口文檔: 音樂地址需要帶id去獲取(但是有的歌曲可能404)https://binaryify.github.io/NeteaseCloudMusicApi/#/?id=%e8%8e%b7%e5%8f%96%e9%9f%b3%e4%b9%90-url--><audioref="audio"preload="true":src="`https://music.163.com/song/media/outer/url?id=${id}.mp3`"></audio></div> </template><script> // 獲取歌曲詳情和 歌曲的歌詞接口 import { getSongByIdAPI, getLyricByIdAPI } from "@/api"; import { Icon } from "vant"; export default {components: {[Icon.name]: Icon,},name: "play",data() {return {playState: false, // 音樂播放狀態(true暫停, false播放)id: this.$route.query.id, // 上一頁傳過來的音樂idsongInfo: {}, // 歌曲信息lyric: {}, // 歌詞枚舉對象(需要在js拿到歌詞寫代碼處理后, 按照格式保存到這個對象)curLyric: "", // 當前顯示哪句歌詞lastLy: "", // 記錄當前播放歌詞};},computed: {needleDeg() {// 留聲機-唱臂的位置屬性return this.playState ? "-7deg" : "-38deg";},},methods: {async getSong() {// 獲取歌曲詳情, 和歌詞方法const res = await getSongByIdAPI(this.id);this.songInfo = res.data.songs[0];// 獲取-并調用_formatLyr方法, 處理歌詞const lyrContent = await getLyricByIdAPI(this.id);const lyricStr = lyrContent.data.lrc.lyric;this.lyric = this._formatLyr(lyricStr);// 初始化完畢先顯示零秒歌詞this.curLyric = this.lyric[0];},_formatLyr(lyricStr) {// 可以看network觀察歌詞數據是一個大字符串, 進行拆分.let reg = /\[.+?\]/g; //let timeArr = lyricStr.match(reg); // 匹配所有[]字符串以及里面的一切內容, 返回數組console.log(timeArr); // ["[00:00.000]", "[00:01.000]", ......]let contentArr = lyricStr.split(/\[.+?\]/).slice(1); // 按照[]拆分歌詞字符串, 返回一個數組(下標為0位置元素不要,后面的留下所以截取)console.log(contentArr);let lyricObj = {}; // 保存歌詞的對象, key是秒, value是顯示的歌詞timeArr.forEach((item, index) => {// 拆分[00:00.000]這個格式字符串, 把分鐘數字取出, 轉換成秒let ms = item.split(":")[0].split("")[2] * 60;// 拆分[00:00.000]這個格式字符串, 把十位的秒拿出來, 如果是0, 去拿下一位數字, 否則直接用2位的值let ss =item.split(":")[1].split(".")[0].split("")[0] === "0"? item.split(":")[1].split(".")[0].split("")[1]: item.split(":")[1].split(".")[0];// 秒數作為key, 對應歌詞作為valuelyricObj[ms + Number(ss)] = contentArr[index];});// 返回得到的歌詞對象(可以打印看看)console.log(lyricObj);return lyricObj;},audioStart() {// 播放按鈕 - 點擊事件if (!this.playState) {// 如果狀態為falsethis.$refs.audio.play(); // 調用audio標簽的內置方法play可以繼續播放聲音} else {this.$refs.audio.pause(); // 暫停audio的播放}this.playState = !this.playState; // 點擊設置對立狀態},showLyric() {// 監聽播放audio進度, 切換歌詞顯示this.$refs.audio.addEventListener("timeupdate", () => {let curTime = Math.floor(this.$refs.audio.currentTime);// 避免空白出現if (this.lyric[curTime]) {this.curLyric = this.lyric[curTime];this.lastLy = this.curLyric;} else {this.curLyric = this.lastLy;}});},},mounted() {this.getSong();this.showLyric();console.log(this.$route.query.id);}, }; </script><style scoped> .header {height: 50px; } .play {position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 1000; } .song-bg {background-color: #161824;background-position: 50%;background-repeat: no-repeat;background-size: auto 100%;transform: scale(1.5);transform-origin: center;position: fixed;left: 0;right: 0;top: 0;height: 100%;overflow: hidden;z-index: 1;opacity: 1;filter: blur(25px); /*模糊背景 */ } .song-bg::before {/*純白色的圖片做背景, 歌詞白色看不到了, 在背景前加入一個黑色半透明蒙層解決 */content: " ";background: rgba(0, 0, 0, 0.5);position: absolute;left: 0;top: 0;right: 0;bottom: 0; } .song-wrapper {position: fixed;width: 247px;height: 247px;left: 50%;top: 50px;transform: translateX(-50%);z-index: 10001; } .song-turn {width: 100%;height: 100%;background: url("./img/bg.png") no-repeat;background-size: 100%; } .start-box {position: absolute;width: 156px;height: 156px;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);display: flex;justify-content: center;align-items: center; } .song-start {width: 56px;height: 56px;background: url("./img/start.png");background-size: 100%; } .needle {position: absolute;transform-origin: left top;background: url("./img/needle-ab.png") no-repeat;background-size: contain;width: 73px;height: 118px;top: -40px;left: 112px;transition: all 0.6s; } .song-img {width: 154px;height: 154px;position: absolute;left: 50%;top: 50%;overflow: hidden;border-radius: 50%;transform: translate(-50%, -50%); } .m-song-h2 {margin-top: 20px;text-align: center;font-size: 18px;color: #fefefe;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; } .lrcContent {margin-top: 50px; } .lrc {font-size: 14px;color: #fff;text-align: center; } .left-incon {position: absolute;top: 10px;left: 10px;font-size: 24px;z-index: 10001;color: #fff; } .ani {animation: turn 5s linear infinite; } @keyframes turn {0% {-webkit-transform: rotate(0deg);}100% {-webkit-transform: rotate(360deg);} } </style>1.4 網易云音樂-路由準備
目標: 準備路由配置, 顯示不同路由頁面
router/index.js - 準備路由 - 以及默認顯示Layout, 然后Layout默認顯示二級路由的首頁
// 路由-相關模塊 import Vue from 'vue' import VueRouter from 'vue-router' import Layout from '@/views/Layout' import Home from '@/views/Home' import Search from '@/views/Search' import Play from '@/views/Play'Vue.use(VueRouter) const routes = [{path: '/',redirect: '/layout'},{path: '/layout',component: Layout,redirect: '/layout/home',children: [{path: 'home',component: Home,meta: { // meta保存路由對象額外信息的title: "首頁"}},{path: 'search',component: Search,meta: {title: "搜索"}}]},{path: '/play',component: Play} ]const router = new VueRouter({routes })export default routermain.js - 引入路由對象, 注冊到new Vue中
import router from '@/router'new Vue({render: h => h(App),router }).$mount('#app')App.vue中留好router-view顯示路由頁面
<template><div><router-view></router-view></div> </template>總結: 把項目的框搭好, 逐個攻破
1.5 網易云音樂-Tabbar組件
目標: 點擊底部導航, 切換路由頁面顯示
文檔: https://vant-contrib.gitee.io/vant/#/zh-CN/tabbar
注冊Tabbar組件, 在main.js中
import { Tabbar, TabbarItem } from 'vant'; Vue.use(Tabbar); Vue.use(TabbarItem);在Layout.vue中使用
<template><div><div class="main"><!-- 二級路由-掛載點 --><router-view></router-view></div><van-tabbar route><van-tabbar-item replace to="/layout/home" icon="home-o">首頁</van-tabbar-item><van-tabbar-item replace to="/layout/search" icon="search">搜索</van-tabbar-item></van-tabbar></div> </template><script> export default { } </script><style scoped> /* 中間內容區域 - 容器樣式(留好上下導航所占位置) */ .main {padding-top: 46px;padding-bottom: 50px; } </style>開啟路由模式 route屬性, 和to屬性指向要切換的路由路徑
<van-tabbar route><van-tabbar-item icon="home-o" to="/layout/home">首頁</van-tabbar-item><van-tabbar-item icon="search" to="/layout/search">搜索</van-tabbar-item> </van-tabbar>總結: van-tabbar開啟route
1.6 網易云音樂-NavBar導航組件
目標: 實現頂部標題展示
文檔: https://vant-contrib.gitee.io/vant/#/zh-CN/nav-bar
main.js - 注冊NavBar組件
import { NavBar } from 'vant'; Vue.use(NavBar);復制文檔里的, 然后刪刪只留標題
<van-nav-bar :title="activeTitle" fixed /><script>export default {activeTitle: "首頁"} </script>1.7 網易云音樂-NavBar標題切換
目標: 實現點擊底部導航/刷新非第一頁面頁面, 導航標題正確顯示
-
在router/index.js - 給$route里需要導航標題的添加meta元信息屬性
{path: '/layout',component: Layout,redirect: '/layout/home',children: [{path: 'home',component: Home,meta: { // meta保存路由對象額外信息的title: "首頁"}},{path: 'search',component: Search,meta: {title: "搜索"}}]},Layout.vue中監聽$route改變:
給導航active的值設置$route里的元信息的標題
export default {data() {return {activeTitle: this.$route.meta.title, // "默認"頂部導航要顯示的標題 (默認獲取當前路由對象里的meta中title值)};},// 路由切換 - 偵聽$route對象改變watch: {$route() {this.activeTitle = this.$route.meta.title; // 提取切換后路由信息對象里的title顯示},}, };
總結: 點擊底部導航和刷新當前網頁, 都能保證導航標題的正確顯示
1.8 網易云音樂-網絡請求封裝
目標: 不想把網絡請求散落在各個邏輯頁面里, 不然以后找起來改起來很麻煩
封裝utils/request.js - 基于axios進行二次封裝 - 設置基礎地址
// 網絡請求 - 二次封裝 import axios from 'axios' axios.defaults.baseURL = "http://localhost:3000" export default axios封裝src/api/Home.js
統一封裝網絡請求方法
// 文件名-盡量和模塊頁面文件名統一(方便查找) import request from '@/utils/request'// 首頁 - 推薦歌單 export const recommendMusic = params => request({url: '/personalized',params// 將來外面可能傳入params的值 {limit: 20} })在src/api/index.js - 統一導出接口供外部使用
// api文件夾下 各個請求模塊js, 都統一來到index.js再向外導出 import {recommendMusic} from './Home'export const recommendMusicAPI = recommendMusic // 請求推薦歌單的方法導出在main.js - 測試使用一下.
import { recommendMusicAPI } from '@/api/index' async function myFn(){const res = await recommendMusicAPI({limit: 6});console.log(res); } myFn();總結: 封裝網絡請求方法目的, 方便我們統一管理
1.9 網易云音樂-首頁-推薦歌單
接口地址: /personalized
布局采用van-row和van-col
布局文檔https://vant-contrib.gitee.io/vant/#/zh-CN/col
使用vant內置的圖片組件來顯示圖片
在main.js注冊使用的組件
import { Col, Row, Image as VanImage } from 'vant';Vue.use(Col); Vue.use(Row); Vue.use(VanImage);在api/index.js下定義推薦歌單的接口方法
// 首頁 - 推薦歌單 export const recommendMusic = params => request({url: '/personalized',params// 將來外面可能傳入params的值 {limit: 20} })把數據請求回來, 用van-image和p標簽展示推薦歌單和歌單名字
<template><div><p class="title">推薦歌單</p><van-row gutter="6"><van-col span="8" v-for="obj in reList" :key="obj.id"><van-image width="100%" height="3rem" fit="cover" :src="obj.picUrl" /><p class="song_name">{{ obj.name }}</p></van-col></van-row></div> </template><script> import { recommendMusicAPI } from "@/api"; export default {data() {return {reList: [], // 推薦歌單數據};},async created() {const res = await recommendMusicAPI({limit: 6,});console.log(res);this.reList = res.data.result;}, }; </script>1.10 網易云音樂- 首頁-最新音樂
目標: van-cell單元格使用
請求地址: /personalized/newsong
引入van-cell使用 - 注冊組件main.js中
import {Cell} from 'vant'; Vue.use(Cell);定義接口請求方法 - api/index.js
// 首頁 - 推薦最新音樂 export const newMusic = params => request({url: "/personalized/newsong",params })列表數據鋪設 - 插入自定義標簽
<template><div><p class="title">推薦歌單</p><div><van-row gutter="5"><van-col span="8" v-for="obj in recommendList" :key="obj.id"><van-image fit="cover" :src="obj.picUrl" /><p class="song_name">{{ obj.name }}</p></van-col></van-row></div><p class="title">最新音樂</p><van-cell center v-for="obj in songList" :key="obj.id" :title="obj.name" :label="obj.song.artists[0].name + ' - ' + obj.name"><template #right-icon><van-icon name="play-circle-o" size="0.6rem"/></template></van-cell></div> </template><script> import { recommendMusicAPI, newMusicAPI } from "@/api"; export default {data() {return {reList: [], // 推薦歌單數據songList: [], // 最新音樂數據};},async created() {const res = await recommendMusicAPI({limit: 6,});console.log(res);this.reList = res.data.result;const res2 = await newMusicAPI({limit: 20})console.log(res2);this.songList = res2.data.result}, }; </script>1.11 網易云音樂-搜索-熱搜關鍵字
目標: 完成熱搜關鍵字鋪設
搜索框 – van-search組件
api/Search.js – 熱搜關鍵字 - 接口方法
Search/index.vue引入-獲取熱搜關鍵字 - 鋪設頁面
點擊文字填充到輸入框
總結: 寫好標簽和樣式, 拿到數據循環鋪設, 點擊關鍵詞填入到van-search中
1.12 網易云音樂-搜索-點擊熱詞-搜索結果
目標: 點擊熱詞填充到輸入框-出搜索結果
api/Search.js - 搜索結果, 接口方法
Search/index.vue引入-獲取搜索結果 - 鋪設頁面
和熱搜關鍵字容器 – 互斥顯示
點擊文字填充到輸入框, 請求搜索結果鋪設
總結: 點擊熱詞后, 調用接口傳入關鍵詞, 返回數據鋪設
1.13 網易云音樂-輸入框-搜索結果
目標: 監測輸入框改變-拿到搜索結果
觀察van-search組件是否支持和實現input事件
綁定@input事件和方法
在事件處理方法中獲取對應的值使用
如果搜索不存在的數據-要注意接口返回字段不同
總結: 監測輸入框改變-保存新的關鍵詞去請求結果回來鋪設
1.14 網易云音樂-搜索結果-加載更多
目標: 觸底后, 加載下一頁數據
觀察接口文檔: 發現需要傳入offset和分頁公式
van-list組件監測觸底執行onload事件
配合后臺接口, 傳遞下一頁的標識
拿到下一頁數據后追加到當前數組末尾即可
總結: list組件負責UI層監測觸底, 執行onload函數, page++, 請求下頁數據, 和現在數據合并顯示更多, 設置loading為false, 確保下次觸底還能執行onLoad
1.15 網易云音樂-加載更多-bug修復
目標: 如果只有一頁數據/無數據判斷
無數據/只有一頁數據, finished為true
防止list組件觸底再加載更多
還要測試-按鈕點擊/輸入框有數據情況的加載更多
正確代碼
async fn(val) {// 點擊熱搜關鍵詞 + this.finished = false; // 點擊新關鍵詞-可能有新的數據this.value = val; // 選中的關鍵詞顯示到搜索框const res = await this.getListFn();console.log(res);this.resultList = res.data.result.songs; + this.loading = false; // 本次數據加載完畢-才能讓list加載更多},async inputFn() { + this.finished = false // 輸入框關鍵字改變-可能有新數據(不一定加載完成了)// 輸入框值改變if (this.value.length === 0) {// 搜索關鍵詞如果沒有, 就把搜索結果清空阻止網絡請求發送(提前return)this.resultList = [];return;}const res = await this.getListFn();console.log(res);+ // 如果搜索結果響應數據沒有songs字段-無數據 + if (res.data.result.songs === undefined) { + this.resultList = []; + return; + }this.resultList = res.data.result.songs; + this.loading = false;},async onLoad() {// 觸底事件(要加載下一頁的數據咯), 內部會自動把loading改為truethis.page++;const res = await this.getListFn(); + if (res.data.result.songs === undefined) { // 沒有更多數據了 + this.finished = true; // 全部加載完成(list不會在觸發onload方法) + this.loading = false; // 本次加載完成 + return; + }this.resultList = [...this.resultList, ...res.data.result.songs]; + this.loading = false; // 數據加載完畢-保證下一次還能觸發onload},總結: 在3個函數 上和下, 設置finished還未完成, 最后要把loading改成false, 判斷songs字段, 對這里的值要非常熟悉才可以
1.16 網易云音樂-輸入框-防抖
目標: 輸入框觸發頻率過高
輸入框輸入"asdfghjkl"
? 接著快速的刪除
? 每次改變-馬上發送網絡請求
? 網絡請求異步耗時 – 數據回來后還是鋪設到頁面上
解決:
? 引入防抖功能
async inputFn() {// 目標: 輸入框改變-邏輯代碼-慢點執行// 解決: 防抖// 概念: 計時n秒, 最后執行一次, 如果再次觸發, 重新計時// 效果: 用戶在n秒內不觸發這個事件了, 才會開始執行邏輯代碼if (this.timer) clearTimeout(this.timer);this.timer = setTimeout(async () => {this.finished = false; // 輸入框關鍵字改變-可能有新數據(不一定加載完成了)// 輸入框值改變if (this.value.length === 0) {// 搜索關鍵詞如果沒有, 就把搜索結果清空阻止網絡請求發送(提前return)this.resultList = [];return;}const res = await this.getListFn();console.log(res);// 如果搜索結果響應數據沒有songs字段-無數據if (res.data.result.songs === undefined) {this.resultList = [];return;}this.resultList = res.data.result.songs;this.loading = false;}, 900); },總結: 降低函數執行頻率
1.17 網易云音樂-頁碼bug修復
目標: 第一個關鍵詞page已經+到了10, 再第二個關鍵詞應該從1開始
加載更多時, page已經往后計數了
重新獲取時, page不是從第一頁獲取的
點擊搜索/輸入框搜索時, 把page改回1
代碼如下:
async fn(val) {// 點擊熱搜關鍵詞 + this.page = 1; // 點擊重新獲取第一頁數據this.finished = false; // 點擊新關鍵詞-可能有新的數據this.value = val; // 選中的關鍵詞顯示到搜索框const res = await this.getListFn();console.log(res);this.resultList = res.data.result.songs;this.loading = false; // 本次數據加載完畢-才能讓list加載更多},async inputFn() {// 目標: 輸入框改變-邏輯代碼-慢點執行// 解決: 防抖// 概念: 計時n秒, 最后執行一次, 如果再次觸發, 重新計時// 效果: 用戶在n秒內不觸發這個事件了, 才會開始執行邏輯代碼if (this.timer) clearTimeout(this.timer);this.timer = setTimeout(async () => { + this.page = 1; // 點擊重新獲取第一頁數據this.finished = false; // 輸入框關鍵字改變-可能有新數據(不一定加載完成了)// 輸入框值改變if (this.value.length === 0) {// 搜索關鍵詞如果沒有, 就把搜索結果清空阻止網絡請求發送(提前return)this.resultList = [];return;}const res = await this.getListFn();console.log(res);// 如果搜索結果響應數據沒有songs字段-無數據if (res.data.result.songs === undefined) {this.resultList = [];return;}this.resultList = res.data.result.songs;this.loading = false;}, 900);},總結: 切換時, 讓page頁面回到1
1.18 網易云音樂-Layout邊距優化
目標: 上下導航會蓋住中間內容
我們的頭部導航和底部導航擋住了中間內容
給中間路由頁面設置上下內邊距即可
在Layout/index.vue中
/* 中間內容區域 - 容器樣式(留好上下導航所占位置) */ .main {padding-top: 46px;padding-bottom: 50px; }1.19 網易云音樂-SongItem封裝
目標: 把首頁和搜索結果的歌曲cell封裝起來
創建src/components/SongItem.vue
<template><van-cell center :title="name" :label="author + ' - ' + name"><template #right-icon><van-icon name="play-circle-o" size="0.6rem"/></template></van-cell> </template><script> export default {props: {name: String, // 歌名author: String, // 歌手id: Number, // 歌曲id (標記這首歌曲-為將來跳轉播放頁做準備)} }; </script><style scoped> /* 給單元格設置底部邊框 */ .van-cell {border-bottom: 1px solid lightgray; } </style>Home/index.vue - 重構
注意: author字段不同
<SongItem v-for="obj in songList":key="obj.id":name="obj.name":author="obj.song.artists[0].name":id="obj.id" ></SongItem>Search/index.vue - 重構
注意: author字段不同
<SongItemv-for="obj in resultList":key="obj.id":name="obj.name":author="obj.ar[0].name":id="obj.id" ></SongItem>總結: 遇到重復標簽要封裝
1.20 網易云音樂-播放音樂
目標: 從預習資料拿到播放的api和頁面, 配置好路由規則
時間關系,這個頁面不用寫, 直接用, 注釋在備課代碼里寫好了
組件SongItem里 – 點擊事件
api/Play.js – 提前準備好 – 接口方法
跳轉到Play頁面 – 把歌曲id帶過進去
在SongItem.vue - 點擊播放字體圖標
methods: {playFn(){this.$router.push({path: '/play',query: {id: this.id // 歌曲id, 通過路由跳轉傳遞過去}})} }總結: 準備好播放頁, 點擊播放傳歌曲id過去, 到播放頁-再請求響應數據和歌曲地址用audio標簽播放
1.21 網易云音樂-vant適配
目標: 切換不同機型, 刷新后看看標簽大小適配嗎
- postcss – 配合webpack翻譯css代碼
- postcss-pxtorem – 配合webpack, 自動把px轉成rem
- 新建postcss.config.js – 設置相關配置
- 重啟服務器, 再次觀察Vant組件是否適配
下載postcss和postcss-pxtorem@5.1.1
postcss作用: 是對css代碼做降級處理
postcss-pxtorem: 自動把所有代碼里的css樣式的px, 自動轉rem
src/新建postcss.config.js
附全文代碼——與案例代碼實現方法不統一
api/Home.js
api/index.js
// api文件夾下 各個請求模塊js, 都統一來到index.js再向外導出 import {recommendMusic, newMusic} from './Home' // import {hotSearch, searchResultList} from './Search' import {getSongById, getLyricById} from './Play'export const recommendMusicAPI = recommendMusic // 請求推薦歌單的方法導出 export const newMusicAPI = newMusic // 首頁 - 最新音樂// export const hotSearchAPI = hotSearch // 搜索 - 熱搜關鍵詞 // export const searchResultListAPI = searchResultList // 搜索 = 搜索結果export const getSongByIdAPI = getSongById // 歌曲 - 播放地址 export const getLyricByIdAPI = getLyricById // 歌曲 - 歌詞數據api/Play.js
import request from '../utils/request'// 播放頁 - 獲取歌曲詳情 export const getSongById = (id) => request({url: `/song/detail?ids=${id}`,method: "GET" })// 播放頁 - 獲取歌詞 export const getLyricById = (id) => request({url: `/lyric?id=${id}`,method: "GET" })api/Search.js
// 搜索模塊 import request from '@/utils/request'// 熱搜關鍵字 export function hotSearch() {return request({// method: 'get'url: '/search/hot'}) }// 搜索結果 export const searchResultList = params => request({url: '/cloudsearch',params })// export const hotSearch = params => request({ // url: '/search/hot', // params // })// 搜索結果 // export const searchResultList = params => request({ // url: '/cloudsearch', // params // })剩下的…可以私信我,我打包了,實在貼不動了
以iphone6為基準, 37.5px為基準值換算rem
今日總結
- 掌握vant組件庫的使用 - 找組件, 引組件, 用組件
- 能夠對vant組件自帶樣式進行覆蓋自定義
- 遇到重復的標簽, 自己也封裝了一個復用的組件
- 掌握查詢文檔和使用每個屬性的方式
總結
以上是生活随笔為你收集整理的调用网易云Api接口实现移动Web网易云部分功能(搜索+列表+播放)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux压缩与解压常用命令
- 下一篇: Charles - 接口抓包分析工具