vite-zmusic/src/views/common/SongCtrl.vue
2021-11-06 17:45:09 +08:00

306 lines
7.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import { useStore } from "vuex";
import { NButton, NIcon, NSpace, useMessage } from "naive-ui";
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
import PlaySkipForward from "@/assets/svgs/PlaySkipForward.svg";
import PlaySkipBack from "@/assets/svgs/PlaySkipBack.svg";
import HeartOutline from "@/assets/svgs/HeartOutline.svg";
import TrashOutline from "@/assets/svgs/TrashOutline.svg";
import PauseCircle from "@/assets/svgs/PauseCircle.svg";
import { getSongUrl } from "@/network/song";
import pubsub from "pubsub-js";
const store = useStore();
const message = useMessage();
// const { settings } = store.state;
const audioEl = ref("");
const playing = ref(false);
let currentTime = 0;
let lastPause = Date.now();
onMounted(() => {
audioEl.value.addEventListener("play", onPlay);
audioEl.value.addEventListener("pause", onPause);
audioEl.value.addEventListener("ended", onEnd);
if (store.state.settings.songId) {
pubsub.publish("zp.play", {
id: store.state.settings.songId,
im: false,
});
// play(settings.songId, false)
}
});
onUnmounted(() => {
// console.log("另外一个Unmounted");
// audioEl.value.removeEventListener("play", onPlay);
// audioEl.value.removeEventListener("pause", onPause);
// audioEl.value.removeEventListener("ended", onEnd);
});
const onPlay = () => {
console.log("onPlay");
};
const onPause = () => {
console.log("onPause");
};
const onEnd = () => {
playNext(1);
// playing.value = false;
currentTime = 0;
console.log("下一首...");
};
//上、下一首
const playNext = async (step) => {
let { songId, playingList, playMode, playing } =
store.state.settings;
let idx = playingList.findIndex((item) => item.id == songId);
// console.log(idx);
switch (playMode) {
case 0: //顺序
idx += step;
if (idx > playingList.length - 1) return;
if (idx < 0) return;
break;
case 1: //循环
idx += step;
if (idx > playingList.length - 1) idx = 0;
if (idx < 0) idx = playingList.length - 1;
break;
case 2: //单曲循环
break;
case 3: //随机
if (playingList.length <= 1) return; //只有一首歌
const i = Math.floor(Math.random() * (playingList.length - 1));
if (i >= idx) idx = i + 1;
else idx = i;
break;
}
// console.log(idx);
play(playingList[idx].id, playing);
};
const previous = async () => {
playNext(-1);
};
const forward = async () => {
playNext(1);
};
const stop = async () => {
pause();
if (store.state.settings.playingList.length < 1) {
audioEl.value.src = "";
lastPause = 0;
store.commit("saveSettings", {
songId: null,
});
pubsub.publish("zp.hideSongInfo");
}
};
const play = async (id, im = true) => {
console.log(id);
await getSongUrl(id)
.then((res) => {
if (null !== res.data.data[0].url) {
audioEl.value.src = res.data.data[0].url;
store.commit("saveSettings", {
songId: id,
});
// console.log(audioEl.value.duration);
pubsub.publish("zp.getSongInfo", {
id: store.state.settings.songId,
im,
});
if (im) {
audioEl.value.play();
playing.value = true;
}
}
})
.catch((err) => {
console.log("getSongUrl err", err);
});
};
const pause = () => {
audioEl.value.pause();
playing.value = false;
};
const resume = async () => {
if (audioEl.value.readyState) {
//如果暂停过了10分钟需要再次载入歌曲
// console.log(Date.now() - lastPause);
if (Date.now() - lastPause > 1000 * 10 * 5) {
console.log("暂停过了10分钟再次载入歌曲");
await play(store.state.settings.songId, false);
// console.log(currentTime);
audioEl.value.currentTime = currentTime;
}
audioEl.value.play();
playing.value = true;
pubsub.publish("zp.getSongInfo", {
id: store.state.settings.songId,
im: true,
});
}
};
const setProgressScale = (scale) => {
if (audioEl.value.readyState) {
// console.log(progress);
audioEl.value.currentTime = currentTime =
scale * audioEl.value.duration;
}
};
const favorite = () => {
// console.log(audioEl.value.currentTime);
};
const removeCurrentSong = () => {
pubsub.publish("zp.removeCurrPlayingSong", {
id: store.state.settings.songId,
});
};
let interval;
watch(playing, (val, old) => {
store.state.settings.playing = val;
if (val === true) {
interval = setInterval(() => {
// console.log(audioEl.value.duration);
if (audioEl.value) {
currentTime = audioEl.value.currentTime;
pubsub.publish("zp.progress", {
progress: audioEl.value.currentTime,
total: audioEl.value.duration,
});
} else clearInterval(interval);
}, 200);
} else {
clearInterval(interval);
lastPause = Date.now();
}
});
//#region 处理消息订阅
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.play":
play(data.id, data.im);
break;
case "zp.next":
forward();
break;
case "zp.previous":
previous();
break;
case "zp.stop":
stop();
break;
case "zp.pause":
if (playing.value) pause();
else resume();
break;
case "zp.setProgressScale":
setProgressScale(data.scale);
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<!-- <div id="songsCtrl"> -->
<audio src="" ref="audioEl"></audio>
<n-space
id="songCtrl"
align="center"
:size="[6]"
style="padding-top: 2px; margin: 0 4px"
>
<n-button circle @click="favorite">
<template #icon>
<n-icon>
<HeartOutline />
</n-icon>
</template>
</n-button>
<n-button circle @click="previous">
<template #icon>
<n-icon>
<PlaySkipBack />
</n-icon>
</template>
</n-button>
<n-button
v-if="!playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="resume"
>
<!-- <template #icon> -->
<n-icon>
<PlayCircle />
</n-icon>
<!-- </template> -->
</n-button>
<n-button
v-if="playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="pause"
>
<!-- <template #icon> -->
<n-icon size="56">
<PauseCircle />
</n-icon>
<!-- </template> -->
</n-button>
<!-- <n-button circle color="#18a058"> -->
<n-button circle @click="forward">
<template #icon>
<n-icon>
<PlaySkipForward />
</n-icon>
</template>
</n-button>
<n-button circle @click="removeCurrentSong">
<template #icon>
<n-icon>
<TrashOutline />
</n-icon>
</template>
</n-button>
</n-space>
<!-- </div> -->
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
#songCtrl {
display: flex;
align-items: center;
}
</style>