refactor(播放器): 优化音频播放逻辑和学生切换功能

- 重构音频播放管理逻辑,简化播放状态控制
- 改进学生切换功能,使用索引代替顺序号
- 移除冗余代码,优化音量控制实现
- 调整CSS布局样式,增强页面展示效果
This commit is contained in:
DESKTOP-RQ919RC\Pc
2025-09-12 18:59:47 +08:00
parent 5a957acf3f
commit 35e3a11427
4 changed files with 51 additions and 62 deletions

View File

@@ -57,7 +57,7 @@
<img class="bj bj1" src="./static/img/album-bj1.svg" /> <img class="bj bj1" src="./static/img/album-bj1.svg" />
<img class="bj bj2" src="./static/img/album-bj2.svg" /> <img class="bj bj2" src="./static/img/album-bj2.svg" />
<div class="album-box" ref="albumBoxRef"> <div class="album-box" ref="albumBoxRef">
<div class="item" v-for="(item, index) in bannerList" :key="index" @click="openPreview(item.id, item.img)"> <div class="item" v-for="(item, index) in bannerList" :key="index" @click="openPreview(item.id)">
<img class="img" :src="item.img" /> <img class="img" :src="item.img" />
<img class="bj bj3" src="./static/img/album-bj3.svg" /> <img class="bj bj3" src="./static/img/album-bj3.svg" />
<img class="bj bj4" src="./static/img/album-bj4.png" /> <img class="bj bj4" src="./static/img/album-bj4.png" />
@@ -68,7 +68,7 @@
</div> </div>
</div> </div>
<div class="trait flexflex mar1200"> <div class="trait flexflex mar1200">
<div class="item flexflex flex1" v-for="(item, index) in trait" :key="index"> <div class="item flexflex" v-for="(item, index) in trait" :key="index">
<img class="icon" :src="item.icon" /> <img class="icon" :src="item.icon" />
<div class="title">{{ item.title }}</div> <div class="title">{{ item.title }}</div>
<div class="text">{{ item.text }}</div> <div class="text">{{ item.text }}</div>
@@ -99,7 +99,7 @@
<div class="time">{{ item.date }}</div> <div class="time">{{ item.date }}</div>
</div> </div>
<div class="media" @click="openPreview(item.id, item.img)"> <div class="media" @click="openPreview(item.id)">
<img class="img" :src="item.img" /> <img class="img" :src="item.img" />
<img class="play" src="./static/img/play-white-icon.svg" /> <img class="play" src="./static/img/play-white-icon.svg" />
</div> </div>
@@ -119,7 +119,7 @@
<div class="name">{{ item.title }}</div> <div class="name">{{ item.title }}</div>
<div class="subtitle">{{ item.desc }}</div> <div class="subtitle">{{ item.desc }}</div>
<div class="time">{{ item.date }}</div> <div class="time">{{ item.date }}</div>
<div class="progress-bar flexacenter"> <div class="progress-bar flexacenter" @click="handleBarDragBottomClick">
<div class="bar white" :style="{ width: item.progress + '%' }"></div> <div class="bar white" :style="{ width: item.progress + '%' }"></div>
<div class="bar black flex1"></div> <div class="bar black flex1"></div>
</div> </div>
@@ -145,7 +145,7 @@
<div class="info flexflex"> <div class="info flexflex">
<div class="name">{{ item.title }}</div> <div class="name">{{ item.title }}</div>
<div class="lyric">{{ item.desc }}</div> <div class="lyric">{{ item.desc }}</div>
<div class="progress-bar flexacenter"> <div class="progress-bar flexacenter" @click="handleBarDragBottomClick">
<div class="bar white" :style="{ width: item.progress + '%' }"></div> <div class="bar white" :style="{ width: item.progress + '%' }"></div>
<div class="bar black flex1"></div> <div class="bar black flex1"></div>
</div> </div>
@@ -172,7 +172,7 @@
<div class="student-box flexflex"> <div class="student-box flexflex">
<img class="title" src="./static/img/student-title.png" alt="" /> <img class="title" src="./static/img/student-title.png" alt="" />
<div class="list flexacenter"> <div class="list flexacenter">
<img class="img" :class="[`img${ item.order }`]" v-for="(item, index) in studentList" :src="item.img" :key="index" @click="cutStudent(item.order)" /> <img class="img" :class="[`img${ item.order }`]" v-for="(item, index) in studentList" :src="item.img" :key="index" @click="cutStudent(index, item.order)" />
</div> </div>
<div class="name">《{{ zeroOrderStudents.title }}》</div> <div class="name">《{{ zeroOrderStudents.title }}》</div>
<div class="info flexacenter"> <div class="info flexacenter">
@@ -180,7 +180,7 @@
{{ zeroOrderStudents.name }} | {{ zeroOrderStudents.age }}岁 | {{ zeroOrderStudents.city }} {{ zeroOrderStudents.name }} | {{ zeroOrderStudents.age }}岁 | {{ zeroOrderStudents.city }}
</div> </div>
<div class="progress-bar flexacenter"> <div class="progress-bar flexacenter" @click="handleBarDragBottomClick">
<div class="bar white" :style="{ width: zeroOrderStudents.progress + '%' }"></div> <div class="bar white" :style="{ width: zeroOrderStudents.progress + '%' }"></div>
<div class="bar black flex1"></div> <div class="bar black flex1"></div>
</div> </div>

View File

@@ -224,6 +224,7 @@
.content .introduce .trait { .content .introduce .trait {
background-color: #ffffff; background-color: #ffffff;
height: 420px; height: 420px;
justify-content: space-between;
} }
.content .introduce .trait .item { .content .introduce .trait .item {
padding-top: 98px; padding-top: 98px;
@@ -244,7 +245,7 @@
margin-bottom: 42px; margin-bottom: 42px;
} }
.content .introduce .trait .item .text { .content .introduce .trait .item .text {
width: 266px; width: 270px;
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;

View File

@@ -255,7 +255,7 @@
.trait { .trait {
background-color: #ffffff; background-color: #ffffff;
height: 420px; height: 420px;
justify-content: space-between;
.item { .item {
padding-top: 98px; padding-top: 98px;
flex-direction: column; flex-direction: column;
@@ -276,7 +276,7 @@
} }
.text { .text {
width: 266px; width: 270px;
font-family: "PingFangSC-Regular", "PingFang SC", sans-serif; font-family: "PingFangSC-Regular", "PingFang SC", sans-serif;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;

View File

@@ -64,7 +64,9 @@ const search = createApp({
if (item.playurl == src) item.progress = val; if (item.playurl == src) item.progress = val;
}); });
if (zeroOrderStudents.value?.playurl == src) zeroOrderStudents.value["progress"] = val; if (zeroOrderStudents.value?.playurl == src) {
zeroOrderStudents.value["progress"] = val;
}
}; };
const introduceRef = ref(null); const introduceRef = ref(null);
@@ -108,6 +110,7 @@ const search = createApp({
const init = () => { const init = () => {
ajax("https://pujianchaoyin.com/api/getHomeData").then((res) => { ajax("https://pujianchaoyin.com/api/getHomeData").then((res) => {
// ajax("https://pujianchaoyin.com/index/api").then((res) => {
if (res.code != 200) return; if (res.code != 200) return;
const data = res.data; const data = res.data;
console.log("data", data); console.log("data", data);
@@ -136,7 +139,9 @@ const search = createApp({
}; };
let bannerSwiperTimer = null; let bannerSwiperTimer = null;
// 头部轮播图 定时器
const bannerSwiper = () => { const bannerSwiper = () => {
clearTimeout(bannerSwiperTimer);
bannerSwiperTimer = setTimeout(() => { bannerSwiperTimer = setTimeout(() => {
let index = pointerIndex.value + 1; let index = pointerIndex.value + 1;
if (index > bannerList.value.length - 1) index = 0; if (index > bannerList.value.length - 1) index = 0;
@@ -145,6 +150,7 @@ const search = createApp({
}, 3000); }, 3000);
}; };
// 头部轮播图 - 切换 定时器
const changeInterval = (type) => { const changeInterval = (type) => {
if (type) clearTimeout(bannerSwiperTimer); if (type) clearTimeout(bannerSwiperTimer);
else bannerSwiper(); else bannerSwiper();
@@ -172,7 +178,7 @@ const search = createApp({
let art = null; let art = null;
// 开启播放 MV // 开启播放 MV
const openPreview = (id, poster = "") => { const openPreview = (id) => {
ajax("https://pujianchaoyin.com/api/getMvDetail", { ajax("https://pujianchaoyin.com/api/getMvDetail", {
id, id,
}).then((res) => { }).then((res) => {
@@ -180,12 +186,13 @@ const search = createApp({
const data = res.data; const data = res.data;
previewState.value = true; previewState.value = true;
nextTick(() => { nextTick(() => {
art = new Artplayer({ art = new Artplayer({
container: ".artplayer-app", container: ".artplayer-app",
url: data.playurl, url: data.playurl,
autoplay: true, autoplay: true,
poster, poster: data.img || "",
fullscreen: true, fullscreen: true,
}); });
art.play(); art.play();
@@ -220,13 +227,16 @@ const search = createApp({
getProgress(); getProgress();
}; };
// 播放 组件数据
let playData = ref(null); let playData = ref(null);
// 管理音频播放
const manageAudio = (src, area) => { const manageAudio = (src, area) => {
const audio = audioPlayer.value; const audio = audioPlayer.value;
closeAll(); closeAll();
nextTick(() => { nextTick(() => {
if (audio?.src != src) audio.src = src; if (audio?.src != src) audio.src = src;
console.log("audio", audio);
audio.play().then(() => { audio.play().then(() => {
if (area == "works") { if (area == "works") {
@@ -262,6 +272,7 @@ const search = createApp({
manageAudio(playurl, area); manageAudio(playurl, area);
}; };
// 关闭所有播放
const closeAll = () => { const closeAll = () => {
audioPlayer.value.pause(); audioPlayer.value.pause();
@@ -275,46 +286,44 @@ const search = createApp({
zeroOrderStudents.value["state"] = false; zeroOrderStudents.value["state"] = false;
console.log("playData", playData);
playData.value && (playData.value.state = false); playData.value && (playData.value.state = false);
}; };
// 定制音乐 数据
let customList = ref([]); let customList = ref([]);
let studentIndex = ref(0); let studentList = ref([]); // 学生数据
let zeroOrderStudents = ref({}); let studentIndex = ref(0); // 学生下标
let zeroOrderStudents = ref({}); // 学生 选中播放 数据
let studentList = ref([]); // 切换学生 播放
const cutStudent = (index) => {
const cutStudent = (order) => {
// 找到目标元素和第一个元素 // 找到目标元素和第一个元素
const [target, first] = [studentList.value.find((item) => item.order == order), studentList.value.find((item) => item.order == 0)]; const [target, first] = [studentList.value[index], studentList.value.find((item) => item.order == 0)];
// 交换order值 // 交换order值
if (target && first && target !== first) [target.order, first.order] = [first.order, target.order]; if (target && first && target !== first) [target.order, first.order] = [first.order, target.order];
console.log("studentList.value", studentList.value);
zeroOrderStudents.value = target; zeroOrderStudents.value = target;
studentIndex.value = index;
target.playurl ? manageAudio(target.playurl, "student") : getPlayUrl(0, "student"); target.playurl ? manageAudio(target.playurl, "student") : getPlayUrl(0, "student");
}; };
// 响应式数据:音量值、是否静音 // 切换学生 歌曲 上\下一首
const volume = ref(84); const cutSong = (type) => {
const isMuted = ref(false); const listLength = studentList.value.length;
const index = studentIndex.value;
let newIndex = 0;
// 切换静音状态的方法 if (type === "up") newIndex = index - 1 < 0 ? listLength - 1 : index - 1;
const toggleMute = () => { else if (type === "down") newIndex = index + 1 >= listLength ? 0 : index + 1;
isMuted.value = !isMuted.value; cutStudent(newIndex);
if (audioPlayer.value) {
audioPlayer.value.muted = isMuted.value;
}
}; };
// 响应式数据:音量值、是否静音
let volume = ref(100);
// 计算并设置音量百分比 // 计算并设置音量百分比
const setVolumePercentage = (percentage) => { const setVolumePercentage = (percentage) => {
// 确保百分比在0-100之间
const volumePercent = Math.max(0, Math.min(100, percentage)); const volumePercent = Math.max(0, Math.min(100, percentage));
volume.value = Math.abs(~~volumePercent); volume.value = Math.abs(~~volumePercent);
@@ -328,11 +337,8 @@ const search = createApp({
const progressBar = event.currentTarget; const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect(); const rect = progressBar.getBoundingClientRect();
// 计算点击位置相对于进度条的比例
// 因为是垂直进度条所以用clientY
const clickPosition = rect.bottom - event.clientY; const clickPosition = rect.bottom - event.clientY;
const percentage = (clickPosition / rect.height) * 100; const percentage = (clickPosition / rect.height) * 100;
console.log("percentage", percentage);
setVolumePercentage(percentage); setVolumePercentage(percentage);
}; };
@@ -436,6 +442,7 @@ const search = createApp({
document.removeEventListener("mouseup", stopBarDragBottom); document.removeEventListener("mouseup", stopBarDragBottom);
}; };
// 直接点击进度条 跳转
const handleBarDragBottomClick = (event) => { const handleBarDragBottomClick = (event) => {
// 获取进度条元素 // 获取进度条元素
const progressBar = event.currentTarget; const progressBar = event.currentTarget;
@@ -476,11 +483,9 @@ const search = createApp({
}; };
const getPlayUrl = (index, area) => { const getPlayUrl = (index, area) => {
console.log("index", index);
let id = null; let id = null;
if (area == "student") { if (area == "student") {
const item = zeroOrderStudents.value; const item = zeroOrderStudents.value;
console.log("item", item.id);
id = item.id; id = item.id;
} }
@@ -489,31 +494,14 @@ const search = createApp({
}).then((res) => { }).then((res) => {
if (res.code != 200) return; if (res.code != 200) return;
const data = res.data; const data = res.data;
console.log("data", data); if (area == "student") {
zeroOrderStudents.value = { ...data, ...zeroOrderStudents.value }; zeroOrderStudents.value = { ...data, ...zeroOrderStudents.value };
manageAudio(data.playurl, area); manageAudio(data.playurl, area);
console.log(zeroOrderStudents.value, "zeroOrderStudents"); console.log(zeroOrderStudents.value, "zeroOrderStudents");
}
}); });
}; };
const cutSong = (type, order) => { return { cutSong, getPlayUrl, handleBarDragBottomClick, startBarDragBottom, volumeShow, handleVolumeHide, handleVolumeShow, zeroOrderStudents, rePlay, playData, awardAudioList, changeInterval, awardMVList, bannerList, albumBoxRef, volume, handleVolumeClick, handleVolumeDrag, startDrag, stopDrag, volume, cutStudent, studentList, studentIndex, scrollToPrevious, scrollToNext, changePointer, pointerIndex, visibleRef, studentRef, customRef, formatTime, currentTimeFormatted, durationFormatted, worksRef, introduceRef, customList, closeAll, manageAudio, progress, closePreview, openPreview, previewState, audioPlayer, trait, fastForward };
const listLength = studentList.value.length;
let newOrder = 0;
if (type === "up") {
// 上一首order减1如果小于0则设置为列表最后一个元素的order
newOrder = order - 1 < 0 ? listLength - 1 : order - 1;
} else if (type === "down") {
// 下一首order加1如果大于等于列表长度则设置为0
newOrder = order + 1 >= listLength ? 0 : order + 1;
}
cutStudent(newOrder);
};
return { cutSong, getPlayUrl, handleBarDragBottomClick, startBarDragBottom, volumeShow, handleVolumeHide, handleVolumeShow, zeroOrderStudents, rePlay, playData, awardAudioList, changeInterval, awardMVList, bannerList, albumBoxRef, volume, handleVolumeClick, handleVolumeDrag, startDrag, stopDrag, toggleMute, isMuted, volume, cutStudent, studentList, studentIndex, scrollToPrevious, scrollToNext, changePointer, pointerIndex, visibleRef, studentRef, customRef, formatTime, currentTimeFormatted, durationFormatted, worksRef, introduceRef, customList, closeAll, manageAudio, progress, closePreview, openPreview, previewState, audioPlayer, trait, fastForward };
}, },
}).mount("#appIndex"); }).mount("#appIndex");