修复bug和优化体验

This commit is contained in:
qier222 2020-10-14 21:10:45 +08:00
parent b399d5bbdc
commit 861125ea8c
17 changed files with 120 additions and 72 deletions

View File

@ -8,39 +8,37 @@
<router-view v-if="!$route.meta.keepAlive"></router-view> <router-view v-if="!$route.meta.keepAlive"></router-view>
</main> </main>
<transition name="slide-up"> <transition name="slide-up">
<BottomBar <Player
v-if="this.$store.state.player.enable" v-if="this.$store.state.player.enable"
ref="player" ref="player"
v-show="this.$route.name !== 'mv'" v-show="this.$route.name !== 'mv'"
/></transition> /></transition>
<GlobalEvents <GlobalEvents :filter="globalEventFilter" @keydown.space="play" />
:filter="(event, handler, eventName) => event.target.tagName !== 'INPUT'"
@keydown.space="play"
/>
</div> </div>
</template> </template>
<script> <script>
import Navbar from "./components/Navbar.vue"; import Navbar from "./components/Navbar.vue";
import BottomBar from "./components/BottomBar.vue"; import Player from "./components/Player.vue";
import GlobalEvents from "vue-global-events"; import GlobalEvents from "vue-global-events";
import { mapState } from "vuex";
export default { export default {
name: "App", name: "App",
components: { components: {
Navbar, Navbar,
BottomBar, Player,
GlobalEvents, GlobalEvents,
}, },
computed: {
...mapState(["loading"]),
},
methods: { methods: {
play(e) { play(e) {
e.preventDefault(); e.preventDefault();
this.$refs.player.play(); this.$refs.player.play();
}, },
globalEventFilter(event) {
if (event.target.tagName === "INPUT") return false;
if (this.$route.name === "mv") return false;
return true;
},
}, },
}; };
</script> </script>

View File

@ -51,7 +51,11 @@ export default {
}, },
methods: { methods: {
goToMv(id) { goToMv(id) {
this.$router.push({ path: "/mv/" + id }); let query = {};
if (this.$parent.player !== undefined) {
query = { autoplay: this.$parent.player.playing };
}
this.$router.push({ path: "/mv/" + id, query });
}, },
getUrl(mv) { getUrl(mv) {
if (mv.cover !== undefined) return mv.cover; if (mv.cover !== undefined) return mv.cover;

View File

@ -104,6 +104,7 @@
</template> </template>
<script> <script>
import { updateMediaSessionMetaData } from "@/utils/mediaSession";
import { mapState, mapMutations, mapActions } from "vuex"; import { mapState, mapMutations, mapActions } from "vuex";
import "@/assets/css/slider.css"; import "@/assets/css/slider.css";
@ -152,14 +153,18 @@ export default {
}, },
methods: { methods: {
...mapMutations([ ...mapMutations([
"updatePlayingStatus",
"updateShuffleStatus", "updateShuffleStatus",
"updatePlayerList", "updatePlayerList",
"shuffleTheList", "shuffleTheList",
"updatePlayerState", "updatePlayerState",
"updateRepeatStatus", "updateRepeatStatus",
]), ]),
...mapActions(["nextTrack", "previousTrack", "playTrackOnListByID"]), ...mapActions([
"nextTrack",
"previousTrack",
"playTrackOnListByID",
"addNextTrackEvent",
]),
play() { play() {
if (this.playing) { if (this.playing) {
this.howler.pause(); this.howler.pause();
@ -168,6 +173,10 @@ export default {
this.playTrackOnListByID(this.player.currentTrack.id); this.playTrackOnListByID(this.player.currentTrack.id);
} }
this.howler.play(); this.howler.play();
if (this.howler._onend.length === 0) {
this.addNextTrackEvent();
updateMediaSessionMetaData(this.player.currentTrack);
}
} }
}, },
next() { next() {

View File

@ -31,6 +31,9 @@ const routes = [
path: "/artist/:id", path: "/artist/:id",
name: "artist", name: "artist",
component: () => import("@/views/artist"), component: () => import("@/views/artist"),
meta: {
keepAlive: true,
},
}, },
{ {
path: "/mv/:id", path: "/mv/:id",

View File

@ -4,7 +4,6 @@ import { updateMediaSessionMetaData } from "@/utils/mediaSession";
export default { export default {
switchTrack({ state, dispatch, commit }, track) { switchTrack({ state, dispatch, commit }, track) {
commit("updateCurrentTrack", track); commit("updateCurrentTrack", track);
commit("updatePlayingStatus", true);
if (track.playable === false) { if (track.playable === false) {
dispatch("nextTrack"); dispatch("nextTrack");
@ -30,23 +29,21 @@ export default {
if (track.playable === false) return; if (track.playable === false) return;
context.dispatch("switchTrack", track); context.dispatch("switchTrack", track);
}, },
nextTrack({ state, dispatch, commit }, realNext = false) { nextTrack({ state, dispatch }, realNext = false) {
let nextTrack = state.player.list.find( let nextTrack = state.player.list.find(
(track) => track.sort === state.player.currentTrack.sort + 1 (track) => track.sort === state.player.currentTrack.sort + 1
); );
if (state.player.repeat === "on" && nextTrack === undefined) {
nextTrack = state.player.list.find((t) => t.sort === 0);
}
if (state.player.repeat === "one" && realNext === false) { if (state.player.repeat === "one" && realNext === false) {
nextTrack = state.player.currentTrack; nextTrack = state.player.currentTrack;
} }
if (state.player.repeat === "off" && nextTrack === undefined) { if (nextTrack === undefined) {
commit("updatePlayingStatus", false); if (state.player.repeat !== "off") {
state.howler.stop(); nextTrack = state.player.list.find((t) => t.sort === 0);
return; } else {
return;
}
} }
dispatch("switchTrack", nextTrack); dispatch("switchTrack", nextTrack);
@ -55,11 +52,18 @@ export default {
let previousTrack = state.player.list.find( let previousTrack = state.player.list.find(
(track) => track.sort === state.player.currentTrack.sort - 1 (track) => track.sort === state.player.currentTrack.sort - 1
); );
if (previousTrack == undefined) {
previousTrack = if (state.player.repeat !== "off") {
previousTrack === null || previousTrack === undefined previousTrack = state.player.list.reduce((x, y) => (x > y ? x : y));
? state.player.list[-1] } else {
: previousTrack; previousTrack = state.player.list.find((t) => t.sort === 0);
}
}
dispatch("switchTrack", previousTrack); dispatch("switchTrack", previousTrack);
}, },
addNextTrackEvent({ state, dispatch }) {
state.howler.once("end", () => {
dispatch("nextTrack");
});
},
}; };

View File

@ -1,7 +1,6 @@
import { Howler } from "howler"; import { Howler } from "howler";
const initState = { const initState = {
loading: true,
Howler: Howler, Howler: Howler,
howler: null, howler: null,
contextMenu: { contextMenu: {

View File

@ -5,9 +5,6 @@ export default {
updatePlayerState(state, { key, value }) { updatePlayerState(state, { key, value }) {
state.player[key] = value; state.player[key] = value;
}, },
updatePlayingStatus(state, status) {
state.player.playing = status;
},
updateCurrentTrack(state, track) { updateCurrentTrack(state, track) {
state.player.currentTrack = track; state.player.currentTrack = track;
}, },

View File

@ -62,3 +62,8 @@ Vue.filter("formatPlayCount", (count) => {
} }
return count; return count;
}); });
Vue.filter("toHttps", (url) => {
if (!url) return "";
return url.replace(/^http:/, "https:");
});

View File

@ -3,7 +3,7 @@ import { getAlbum } from "@/api/album";
import { getPlaylistDetail } from "@/api/playlist"; import { getPlaylistDetail } from "@/api/playlist";
import { getTrackDetail } from "@/api/track"; import { getTrackDetail } from "@/api/track";
import { getArtist } from "@/api/artist"; import { getArtist } from "@/api/artist";
import { trackFee } from "@/utils/common"; import { isTrackPlayable } from "@/utils/common";
export function playAList(list, id, type, trackID = "first") { export function playAList(list, id, type, trackID = "first") {
let filteredList = list.map((track, index) => { let filteredList = list.map((track, index) => {
@ -14,7 +14,7 @@ export function playAList(list, id, type, trackID = "first") {
artists: track.ar, artists: track.ar,
album: track.al, album: track.al,
time: track.dt, time: track.dt,
playable: trackFee(track).playable, playable: isTrackPlayable(track).playable,
}; };
}); });

View File

@ -126,7 +126,7 @@ export default {
}); });
}, },
computed: { computed: {
...mapState(["player", "loading"]), ...mapState(["player"]),
albumTime() { albumTime() {
let time = 0; let time = 0;
this.tracks.map((t) => (time = time + t.dt)); this.tracks.map((t) => (time = time + t.dt));

View File

@ -109,6 +109,7 @@ export default {
components: { Cover, ButtonTwoTone, TrackList, CoverRow, MvRow }, components: { Cover, ButtonTwoTone, TrackList, CoverRow, MvRow },
data() { data() {
return { return {
show: false,
artist: { artist: {
img1v1Url: img1v1Url:
"https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg", "https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg",
@ -124,13 +125,9 @@ export default {
size: "", size: "",
}, },
showMorePopTracks: false, showMorePopTracks: false,
show: false,
mvs: [], mvs: [],
}; };
}, },
created() {
this.loadData(this.$route.params.id);
},
computed: { computed: {
...mapState(["player"]), ...mapState(["player"]),
albums() { albums() {
@ -153,8 +150,8 @@ export default {
getArtist(id).then((data) => { getArtist(id).then((data) => {
this.artist = data.artist; this.artist = data.artist;
this.popularTracks = data.hotSongs; this.popularTracks = data.hotSongs;
if (next !== undefined) next();
this.popularTracks = mapTrackPlayableStatus(this.popularTracks); this.popularTracks = mapTrackPlayableStatus(this.popularTracks);
if (next !== undefined) next();
NProgress.done(); NProgress.done();
this.show = true; this.show = true;
}); });
@ -176,6 +173,18 @@ export default {
playAList(this.popularTracks, this.artist.id, "artist", trackID); playAList(this.popularTracks, this.artist.id, "artist", trackID);
}, },
}, },
created() {
this.loadData(this.$route.params.id);
},
activated() {
if (this.show) {
if (this.artist.id.toString() !== this.$route.params.id) {
this.show = false;
NProgress.start();
this.loadData(this.$route.params.id);
}
}
},
beforeRouteUpdate(to, from, next) { beforeRouteUpdate(to, from, next) {
NProgress.start(); NProgress.start();
this.artist.img1v1Url = this.artist.img1v1Url =

View File

@ -64,6 +64,7 @@ export default {
}, },
data() { data() {
return { return {
show: false,
playlists: [], playlists: [],
activeCategory: "全部", activeCategory: "全部",
loadingMore: false, loadingMore: false,
@ -81,6 +82,7 @@ export default {
}, },
methods: { methods: {
loadData() { loadData() {
if (!this.show) NProgress.start();
this.activeCategory = this.activeCategory =
this.$route.query.category === undefined this.$route.query.category === undefined
? "全部" ? "全部"
@ -95,6 +97,7 @@ export default {
this.loadingMore = false; this.loadingMore = false;
this.showLoadMoreButton = true; this.showLoadMoreButton = true;
NProgress.done(); NProgress.done();
this.show = true;
}, },
getPlaylist() { getPlaylist() {
this.loadingMore = true; this.loadingMore = true;

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="home"> <div class="home" v-show="show">
<div class="index-row"> <div class="index-row">
<div class="title"> <div class="title">
by Apple Music by Apple Music
@ -57,6 +57,7 @@ import { toplists, recommendPlaylist } from "@/api/playlist";
import { toplistOfArtists } from "@/api/artist"; import { toplistOfArtists } from "@/api/artist";
import { byAppleMusic } from "@/utils/staticPlaylist"; import { byAppleMusic } from "@/utils/staticPlaylist";
import { newAlbums } from "@/api/album"; import { newAlbums } from "@/api/album";
import NProgress from "nprogress";
import CoverRow from "@/components/CoverRow.vue"; import CoverRow from "@/components/CoverRow.vue";
@ -65,6 +66,7 @@ export default {
components: { CoverRow }, components: { CoverRow },
data() { data() {
return { return {
show: false,
recommendPlaylist: { name: "推荐歌单", items: [] }, recommendPlaylist: { name: "推荐歌单", items: [] },
newReleasesAlbum: { name: "新专速递", items: [] }, newReleasesAlbum: { name: "新专速递", items: [] },
topList: { topList: {
@ -86,10 +88,13 @@ export default {
}, },
methods: { methods: {
loadData() { loadData() {
if (!this.show) NProgress.start();
recommendPlaylist({ recommendPlaylist({
limit: 10, limit: 10,
}).then((data) => { }).then((data) => {
this.recommendPlaylist.items = data.result; this.recommendPlaylist.items = data.result;
NProgress.done();
this.show = true;
}); });
newAlbums({ newAlbums({
area: "EA", area: "EA",

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div v-show="show">
<h1> <h1>
<img class="head" :src="user.profile.avatarUrl | resizeImage" />{{ <img class="head" :src="user.profile.avatarUrl | resizeImage" />{{
user.profile.nickname user.profile.nickname
@ -59,6 +59,7 @@ import { userDetail, userPlaylist } from "@/api/user";
import { mapTrackPlayableStatus, randomNum } from "@/utils/common"; import { mapTrackPlayableStatus, randomNum } from "@/utils/common";
import { getPlaylistDetail } from "@/api/playlist"; import { getPlaylistDetail } from "@/api/playlist";
import { playPlaylistByID } from "@/utils/play"; import { playPlaylistByID } from "@/utils/play";
import NProgress from "nprogress";
import TrackList from "@/components/TrackList.vue"; import TrackList from "@/components/TrackList.vue";
import CoverRow from "@/components/CoverRow.vue"; import CoverRow from "@/components/CoverRow.vue";
@ -69,6 +70,7 @@ export default {
components: { SvgIcon, CoverRow, TrackList }, components: { SvgIcon, CoverRow, TrackList },
data() { data() {
return { return {
show: false,
user: { user: {
profile: { profile: {
avatarUrl: "", avatarUrl: "",
@ -82,6 +84,7 @@ export default {
}; };
}, },
created() { created() {
NProgress.start();
userDetail(this.settings.user.userId).then((data) => { userDetail(this.settings.user.userId).then((data) => {
this.user = data; this.user = data;
}); });
@ -135,6 +138,7 @@ export default {
let oldTracks = this.likedSongs.tracks; let oldTracks = this.likedSongs.tracks;
this.likedSongs = data.playlist; this.likedSongs = data.playlist;
this.likedSongs.tracks = oldTracks; this.likedSongs.tracks = oldTracks;
this.getMoreLikedSongs(); this.getMoreLikedSongs();
this.getRandomLyric(); this.getRandomLyric();
}); });
@ -144,6 +148,8 @@ export default {
getTrackDetail(TrackIDs.join(",")).then((data) => { getTrackDetail(TrackIDs.join(",")).then((data) => {
this.likedSongs.tracks = data.songs; this.likedSongs.tracks = data.songs;
this.likedSongs.tracks = mapTrackPlayableStatus(this.likedSongs.tracks); this.likedSongs.tracks = mapTrackPlayableStatus(this.likedSongs.tracks);
NProgress.done();
this.show = true;
}); });
}, },
getRandomLyric() { getRandomLyric() {

View File

@ -62,17 +62,16 @@ export default {
Promise.all(requests).then((results) => { Promise.all(requests).then((results) => {
let sources = results.map((result) => { let sources = results.map((result) => {
return { return {
src: result.data.url, src: result.data.url.replace(/^http:/, "https:"),
type: "video/mp4", type: "video/mp4",
size: result.data.r, size: result.data.r,
}; };
}); });
console.table(sources);
this.player.source = { this.player.source = {
type: "video", type: "video",
title: this.mv.data.name, title: this.mv.data.name,
sources: sources, sources: sources,
poster: this.mv.data.cover, poster: this.mv.data.cover.replace(/^http:/, "https:"),
}; };
NProgress.done(); NProgress.done();
}); });
@ -82,10 +81,6 @@ export default {
}); });
}, },
}, },
created() {
if (this.$route.query.autoplay === "true")
this.videoOptions.autoplay = true;
},
mounted() { mounted() {
let videoOptions = { let videoOptions = {
settings: ["quality"], settings: ["quality"],
@ -95,8 +90,12 @@ export default {
options: [1080, 720, 480, 240], options: [1080, 720, 480, 240],
}, },
}; };
if (this.$route.query.autoplay === "true") videoOptions.autoplay = true;
this.player = new Plyr(this.$refs.videoPlayer, videoOptions); this.player = new Plyr(this.$refs.videoPlayer, videoOptions);
this.player.volume = this.$store.state.player.volume; this.player.volume = this.$store.state.player.volume;
this.player.on("playing", () => {
this.$store.state.howler.pause();
});
this.getData(this.$route.params.id); this.getData(this.$route.params.id);
console.log("网易云你这mv音频码率也太糊了吧🙄"); console.log("网易云你这mv音频码率也太糊了吧🙄");
}, },
@ -149,7 +148,6 @@ export default {
.section-title { .section-title {
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
margin-bottom: 16px;
color: rgba(0, 0, 0, 0.88); color: rgba(0, 0, 0, 0.88);
} }
} }

View File

@ -94,6 +94,7 @@ export default {
}, },
data() { data() {
return { return {
show: false,
playlist: { playlist: {
coverImgUrl: "", coverImgUrl: "",
creator: { creator: {
@ -105,29 +106,10 @@ export default {
tracks: [], tracks: [],
loadingMore: false, loadingMore: false,
lastLoadedTrackIndex: 9, lastLoadedTrackIndex: 9,
show: false,
}; };
}, },
created() { created() {
this.id = this.$route.params.id; this.loadData(this.$route.params.id);
getPlaylistDetail(this.id)
.then((data) => {
this.playlist = data.playlist;
this.tracks = data.playlist.tracks;
this.tracks = mapTrackPlayableStatus(this.tracks);
NProgress.done();
this.show = true;
if (this.playlist.trackCount > this.tracks.length) {
window.addEventListener("scroll", this.handleScroll, true);
}
return data;
})
.then(() => {
if (this.playlist.trackCount > this.tracks.length) {
this.loadingMore = true;
this.loadMore();
}
});
}, },
destroyed() { destroyed() {
window.removeEventListener("scroll", this.handleScroll, true); window.removeEventListener("scroll", this.handleScroll, true);
@ -149,6 +131,29 @@ export default {
this.playPlaylistByID(); this.playPlaylistByID();
this.shuffleTheList(); this.shuffleTheList();
}, },
loadData(id, next = undefined) {
console.log("loadData");
this.id = id;
getPlaylistDetail(this.id)
.then((data) => {
this.playlist = data.playlist;
this.tracks = data.playlist.tracks;
this.tracks = mapTrackPlayableStatus(this.tracks);
NProgress.done();
if (next !== undefined) next();
this.show = true;
if (this.playlist.trackCount > this.tracks.length) {
window.addEventListener("scroll", this.handleScroll, true);
}
return data;
})
.then(() => {
if (this.playlist.trackCount > this.tracks.length) {
this.loadingMore = true;
this.loadMore();
}
});
},
loadMore() { loadMore() {
let trackIDs = this.playlist.trackIds.filter((t, index) => { let trackIDs = this.playlist.trackIds.filter((t, index) => {
if ( if (

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="search"> <div class="search" v-show="show">
<h1><span>Search for</span> "{{ keywords }}"</h1> <h1><span>Search for</span> "{{ keywords }}"</h1>
<div class="result" v-if="result !== undefined"> <div class="result" v-if="result !== undefined">
<div class="row"> <div class="row">
@ -135,6 +135,7 @@ export default {
}, },
data() { data() {
return { return {
show: false,
result: {}, result: {},
mvs: [], mvs: [],
type: 1, type: 1,
@ -164,6 +165,7 @@ export default {
search({ keywords: keywords, type: 1018 }).then((data) => { search({ keywords: keywords, type: 1018 }).then((data) => {
this.result = data.result; this.result = data.result;
NProgress.done(); NProgress.done();
this.show = true;
}); });
search({ keywords: keywords, type: 1004 }).then((data) => { search({ keywords: keywords, type: 1004 }).then((data) => {
this.mvs = data.result.mvs; this.mvs = data.result.mvs;
@ -174,6 +176,7 @@ export default {
this.getData(this.$route.query.keywords); this.getData(this.$route.query.keywords);
}, },
beforeRouteUpdate(to, from, next) { beforeRouteUpdate(to, from, next) {
this.show = false;
next(); next();
NProgress.start(); NProgress.start();
this.getData(to.query.keywords); this.getData(to.query.keywords);