Vue3.0 + typescript 高仿網易雲音樂 WebApp
技術標籤:vuevue.jstypescriptjavascriptes6sass
Vue3.0 + typescript 高仿網易雲音樂 WebApp
前言
Vue3.0 的正式釋出,讓我心動不已,於是嘗試用 vue3 實現一個完整的專案,整個專案全部使用了 composition api, 相比較 options 方式,邏輯更加清晰,使用也更加靈活。
先貼上地址,喜歡的可以 star 一波
原始碼地址 : https://github.com/bianyingchun/vue3-music
這裡還有 react hooks 版本
專案介紹
本專案是使用 vue-cli 4.5 搭建的專案, vue-router 以及 vuex 均為 4.0 版本,以支援 composition api 的使用。使用 typescript 編寫完成。該專案的所有資料介面來自大佬 binaryify 的
本專案將會持續維護開發中,目前實現了以下模組:
滾動載入更多
這個專案中幾乎所有的列表頁都使用到了滾動載入更多的邏輯,於是我封裝了一個公共 hooks,以供複用
import _ from 'lodash'
import { Ref, onMounted, onUnmounted } from 'vue'
export function useLoadMore(
refreshElm: Ref<null | HTMLElement>,
loadData: () => any
) {
let element: HTMLElement
const _loadMore = _.throttle(() => {
const containerHeight = element.clientHeight
const scrollTop = element.scrollTop
const scrollHeight = element.scrollHeight
if (containerHeight + scrollTop + 20 >= scrollHeight) {
loadData()
}
}, 200)
onMounted(() => {
element = refreshElm.value as HTMLElement
element.addEventListener('scroll', _loadMore)
})
onUnmounted(() => {
element.removeEventListener('scroll', _loadMore)
})
return {}
}
主題切換
通過 css 變數和 sass mixin 的結合,實現了明暗主題的切換,當然你可以定義不同的主題。
@mixin css-var(
$text,
$text-reversal,
$text-nav,
$header-bg,
$text-secondary,
$primary,
$link-bg,
$body-bg,
$module-bg,
$border
) {
#{--body-bg}: $body-bg;
#{--text}: $text;
#{--text-reversal}: $text-reversal;
#{--text-nav}: $text-nav;
#{--text-secondary}: $text-secondary;
#{--primary}: $primary;
#{--header-bg}: $header-bg;
#{--link-bg}: $link-bg;
#{--module-bg}: $module-bg;
#{--border}: $border;
#{--bg-reversal-opacity-9}: rgba($text, 0.9);
}
.light {
@include css-var(
$text: #333,
$text-reversal: #fff,
$text-nav: #5d5d5d,
$text-secondary: #888,
$primary: #d23931,
//active
$link-bg: #f34d3f,
$header-bg: #da3d34,
$body-bg: #f0f0f0,
$module-bg: #fff,
$border: #ccc
);
}
.dark {
@include css-var(
$text: #fff,
$text-reversal: #333,
$text-nav: #d7d7d7,
$text-secondary: #ccc,
$primary: #f1423d,
$link-bg: #414141,
$header-bg: #414141,
$body-bg: #262626,
$module-bg: #2c2c2c,
$border: #4e4a4a
);
}
登入
通過登入以體驗更豐富的功能,如發表評論,點贊,關注使用者,歌手,收藏歌曲,建立歌單等。在未登入狀態下觸及到這些功能時會自動顯示登入介面,登入成功後會返回到當前頁面,重新整理當前使用者狀態。
為了共享使用者狀態,我將使用者狀態儲存到 store 中,並抽離出公共邏輯 useAuth.ts
export function useAuth(store: Store<GlobalState>) {
const account = computed(() => store.state.auth.account);
const profile = computed(() => store.state.auth.profile);
const toggleLoginBox = (val: boolean) =>
store.commit(`auth/${SET_LOGIN_VISIBLE}`, val);
return {
account,
profile,
toggleLoginBox,
};
}
個人中心
在使用者登入成功,個人中心會顯示使用者資訊,以及個人建立和收藏的歌單, 使用者可以建立、刪除、編輯歌單、取消收藏的歌單。
播放器
播放器算是此專案中最核心的模組了。實現了一個播放器應該有的基本功能。
- 列表播放
- 插入歌曲
- 切換歌曲
- 從播放列表中刪除歌曲
- 清空播放列表
- 切換播放模式
- 歌詞同步
- 調整播放進度
- 新增到歌單
由於在多個頁面中使用到了播放歌曲的功能,我抽離出了公共邏輯 usePlayMusic.ts
export function usePlayMusic(store: Store<GlobalState>) {
const playing = computed(() => store.state.player.playing);
const currentSong = computed(() => store.getters["player/currentSong"]);
function selectPlay(list: Track[], index: number) {
store.dispatch("player/selectPlay", {
list,
index,
});
}
function insertSong(song: Track) {
store.dispatch("player/insertSong", song);
}
return {
currentSong,
insertSong,
selectPlay,
playing,
};
}
在實現收藏歌曲到歌單時,考慮到這個功能多次被使用,且無需反覆建立,故設計為公共單例元件,並封裝成 hooks,方便呼叫。
import { ref, createApp, App, h } from "vue";
import Comp from "@/components/achive/fav-to-mix.vue";
import { useMylist } from "./usePlaylist";
import { useAuth } from "./useAuth";
import { Track, Playlist } from "@/types";
import store from "@/store";
let favToMixVm: App | null = null;
const show = ref(false);
function hide() {
show.value = false;
}
export function favTrackToMix(track: Track) {
const { account, toggleLoginBox } = useAuth(store);
if (!account.value) return toggleLoginBox(true);
show.value = true;
const { likelist, createdList, addTrack } = useMylist(store);
const list = likelist.value
? [likelist.value, ...createdList.value]
: createdList.value;
async function onSelect(mix: Playlist) {
show.value = false;
await addTrack(mix.id, track);
}
if (!favToMixVm) {
favToMixVm = createApp({
setup() {
return () =>
h(Comp, {
show: show.value,
list,
hide,
onSelect,
});
},
});
const el = document.createElement("div");
document.body.appendChild(el);
favToMixVm.mount(el);
}
}
搜尋
搜尋頁面中,實現功能的功能有
- 搜尋歌手、歌單、歌曲、使用者
- 搜尋提示(函式防抖)
- 熱門搜尋、歷史搜尋
歌單詳情
在歌單頁面中,可以收藏和取消收藏其他使用者的歌單,點選歌曲可以播放整個歌單歌曲列表,如果是自己的歌單可以將歌曲從歌單中刪除。補充:排行榜的詳情頁以及每日推薦其實也是歌單,只是歌曲樣式稍有不同。
評論
歌曲和歌單的評論是同一個元件,只是傳入的引數不同。
實現的功能有
- 評論列表
- 釋出評論
- 回覆評論
- 查看回複列表
- 點贊評論
- 刪除自己釋出的評論
使用者主頁
關注/粉絲列表
歌手主頁
歌手主頁和使用者主頁使用的是同一個佈局元件,通過傳入 slot 插槽, 呈現不同的主體。
歌手分類
歌單廣場
排行榜
專案執行
-
克隆到本地
git clone https://github.com/bianyingchun/react-music.git -
安裝依賴
yarn install -
執行
yarn serve -
打包
yarn build