Files
PC-official/static/js/song-request-station.js
DESKTOP-RQ919RC\Pc 8a764d2fdb feat: 更新音乐播放器界面和功能
- 调整播放器底部样式,优化进度条和操作按钮布局
- 修复音量控制拖动功能
- 更新音乐数据源,增加更多歌曲分类和曲目
- 优化图片资源路径和命名规范
- 添加新的SVG图标和背景元素
- 修复播放进度条选择器错误
- 调整标签样式和交互效果
2025-09-23 12:18:14 +08:00

346 lines
13 KiB
JavaScript
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.

const { createApp, ref, onMounted, nextTick, onUnmounted, computed } = Vue;
const search = createApp({
setup() {
// 标签数据
let tags = ref([]);
let tagsFill = ref([]);
// 获取容器
const containerFill = ref(null);
const container = ref(null);
// 计算容器尺寸
const getContainerDimensions = () => {
const containerWidth = container.value.offsetWidth;
const containerHeight = container.value.offsetHeight;
return { containerWidth, containerHeight };
};
// 初始创建标签
const init = () => {
fetch("./static/js/music.json")
.then((response) => {
if (!response.ok) throw new Error(`请求失败:${response.status}`);
// 将响应解析为 JSON 格式
return response.json();
})
.then((data) => {
// 成功获取 JSON 数据,后续处理(如使用 tags 数组)
console.log("读取到的 JSON 数据:", data);
// data.data.length = 1
let tagsData = data.data || []; // 提取 tags 数组
console.log("tagsData", tagsData);
const { containerWidth, containerHeight } = getContainerDimensions();
const redCount = Math.min(5, tagsData.length);
const redIndexes = [];
while (redIndexes.length < redCount) {
const randomIdx = Math.floor(Math.random() * tagsData.length);
if (!redIndexes.includes(randomIdx)) redIndexes.push(randomIdx);
}
tagsData.forEach((item, index) => {
item["type"] = getRandomOutcome();
if (redIndexes.includes(index)) item["isred"] = 1;
});
tags.value = tagsData;
const fillLength = tags.value.length * 1.5;
let tagAll = [];
for (let i = 0; i < fillLength; i++) {
tagAll.push({
type: Math.floor(Math.random() * 5) + 1,
});
}
tagsFill.value = tagAll;
nextTick(() => {
tagCloud({
selector: "#bubbleContainerFill", // 元素选择器id 或 class
radius: [containerWidth / 2, containerHeight / 2], // 滚动横/纵轴半径, 默认60单位px取值60[60][60, 60]
mspeed: "normal", // 滚动最大速度, 取值: slow, normal(默认), fast
ispeed: "slow", // 滚动初速度, 取值: slow, normal(默认), fast
direction: 45, // 初始滚动方向, 取值角度(顺时针360): 0对应top, 90对应left, 135对应right-bottom(默认)...
keep: false, // 鼠标移出组件后是否继续随鼠标滚动, 取值: false, true(默认) 对应 减速至初速度滚动, 随鼠标滚动
multicolour: false, // 彩色字体颜色随机取值true(默认),false
});
tagCloud({
selector: "#bubbleContainer", // 元素选择器id 或 class
radius: [containerWidth / 2, containerHeight / 2],
mspeed: "normal",
ispeed: "normal",
direction: 135,
keep: false,
multicolour: false,
});
});
});
};
// 生成单次随机结果的函数
const getRandomOutcome = () => {
const random = Math.random(); // 生成0-1之间的随机数
let cumulativeProbability = 0;
const outcomes = [0.1, 0.2, 0.3, 0.4];
for (const outcome of outcomes) {
cumulativeProbability += outcome;
if (random < cumulativeProbability) {
return outcomes.indexOf(outcome) + 1;
}
}
};
onMounted(() => {
init();
// 添加进度更新事件监听器
if (audioPlayer.value) {
volume.value = audioPlayer.value.volume * 100;
audioPlayer.value.addEventListener("timeupdate", getProgress);
audioPlayer.value.addEventListener("loadedmetadata", getProgress);
}
});
// 组件卸载时清理事件监听器
onUnmounted(() => {
audioPlayer?.value?.removeEventListener("timeupdate", getProgress);
audioPlayer?.value?.removeEventListener("loadedmetadata", getProgress);
});
const handleMouseleave = (e) => {
e.target.style.animationPlayState = "running";
};
const handleMouseenter = (e) => {
e.target.style.animationPlayState = "paused";
};
const audioPlayer = ref(null);
const clickSongs = (songs) => {
const randomIndex = Math.floor(Math.random() * songs.length);
const item = songs[randomIndex];
manageAudio(item);
};
// 管理音频播放
const manageAudio = (item) => {
const audio = audioPlayer.value;
closeAll();
setTimeout(() => {
console.log("item", item);
if (audio?.src != item.path) audio.src = item.path;
// audio.src = "https://app.gter.net/image/miniApp/mp3/1.mp3";
audio.src = "/static/mp3/1.MP3";
audio.play().then(() => (playData.value = { ...item, state: true }));
}, 500);
};
// 重新播放
const rePlay = () => {
if (!playData.value) return;
const item = playData.value;
manageAudio(item);
};
// 播放 组件数据
let playData = ref(null);
// 响应式数据:音量值、是否静音
let volume = ref(100);
// 计算并设置音量百分比
const setVolumePercentage = (percentage) => {
const volumePercent = Math.max(0, Math.min(100, percentage));
volume.value = Math.abs(~~volumePercent);
// 设置音频元素的音量范围是0-1
if (audioPlayer.value) audioPlayer.value.volume = volume.value / 100;
};
// 处理音量进度条点击
const handleVolumeClick = (event) => {
// 获取进度条元素
const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect();
const clickPosition = rect.bottom - event.clientY;
const percentage = (clickPosition / rect.height) * 100;
setVolumePercentage(percentage);
};
let volumeShow = ref(false);
// 处理音量进度条拖拽
let isDragging = false;
const startDrag = (event) => {
isDragging = true;
handleVolumeDrag(event);
// 添加事件监听器
document.addEventListener("mousemove", handleVolumeDrag);
document.addEventListener("mouseup", stopDrag);
};
const handleVolumeDrag = (event) => {
if (!isDragging) return;
// 获取音量进度条元素
const progressBar = document.querySelector(".sound-control .progress");
if (!progressBar) return;
const rect = progressBar.getBoundingClientRect();
// 计算拖拽位置相对于进度条的比例
let dragPosition = rect.bottom - event.clientY;
// 限制在进度条范围内
dragPosition = Math.max(0, Math.min(dragPosition, rect.height));
const percentage = (dragPosition / rect.height) * 100;
setVolumePercentage(percentage);
};
const stopDrag = () => {
isDragging = false;
document.removeEventListener("mousemove", handleVolumeDrag);
document.removeEventListener("mouseup", stopDrag);
};
const handleVolumeShow = () => (volumeShow.value = true);
const handleVolumeHide = () => (volumeShow.value = false);
onUnmounted(() => {
// 确保移除所有拖拽相关事件
document.removeEventListener("mousemove", handleVolumeDrag);
document.removeEventListener("mouseup", stopDrag);
document.removeEventListener("mousemove", handleBarDragBottomDrag);
document.removeEventListener("mouseup", stopBarDragBottom);
});
const progress = ref(0); // 播放进度百分比
// 响应式变量存储当前播放时间和总时长
const currentTimeFormatted = ref("00:00");
const durationFormatted = ref("00:00");
// 格式化时间函数:将秒数转换为 MM:SS 格式
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
};
// 更新进度的函数
const getProgress = () => {
if (!audioPlayer.value) return;
const currentTime = audioPlayer.value.currentTime || 0;
const duration = audioPlayer.value.duration || 0;
const p = duration > 0 ? (currentTime / duration) * 100 : 0;
progress.value = p;
// 更新时间显示
currentTimeFormatted.value = formatTime(currentTime);
durationFormatted.value = formatTime(duration);
};
// 快进 和 后退 10秒
const fastForward = (type = "fast") => {
if (!audioPlayer.value) return;
console.log("playData.value", playData.value);
const src = playData.value?.path || "";
if (audioPlayer.value.src != src) {
manageAudio(playData.value);
return;
}
let currentTime = audioPlayer.value.currentTime || 0;
const duration = audioPlayer.value.duration || 0;
let newTime = 0;
if (type == "fast") newTime = Math.min(currentTime + 10, duration);
else newTime = Math.max(currentTime - 10, 0);
audioPlayer.value.currentTime = newTime;
getProgress();
};
// 关闭所有播放
const closeAll = () => {
audioPlayer.value.pause();
playData.value && (playData.value.state = false);
};
// 处理音量进度条拖拽
let isBarBottomDragging = false;
const startBarDragBottom = (event) => {
isBarBottomDragging = true;
handleBarDragBottomDrag(event);
// 添加事件监听器
document.addEventListener("mousemove", handleBarDragBottomDrag);
document.addEventListener("mouseup", stopBarDragBottom);
};
const stopBarDragBottom = () => {
isBarBottomDragging = false;
document.removeEventListener("mousemove", handleBarDragBottomDrag);
document.removeEventListener("mouseup", stopBarDragBottom);
};
// 直接点击进度条 跳转
const handleBarDragBottomClick = (event) => {
// 获取进度条元素
const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect();
const clickPosition = event.clientX - rect.left;
const percentage = clickPosition / rect.width;
// 限制百分比在0-100之间
const clampedPercentage = Math.max(0, Math.min(100, percentage));
updatePlay(clampedPercentage);
};
const handleBarDragBottomDrag = (event) => {
// console.log("event", event);
if (!isBarBottomDragging) return;
// 获取音量进度条元素
const progressBar = document.querySelector(".bottom-play .bottom-middle .progress-bar");
if (!progressBar) return;
console.log("14111111111");
const rect = progressBar.getBoundingClientRect();
// 计算拖拽位置相对于进度条的比例
let dragPosition = event.clientX - rect.left;
// 限制在进度条范围内
dragPosition = Math.max(0, Math.min(dragPosition, rect.width));
const percentage = dragPosition / rect.width;
updatePlay(percentage);
};
const updatePlay = (percentage) => {
if (!audioPlayer.value) return;
const duration = audioPlayer.value.duration || 0;
let newTime = duration * percentage;
newTime = Math.max(0, Math.min(duration, newTime));
audioPlayer.value.currentTime = newTime;
getProgress();
};
return { startBarDragBottom, handleBarDragBottomClick, closeAll, fastForward, progress, durationFormatted, currentTimeFormatted, rePlay, handleVolumeHide, handleVolumeShow, stopDrag, handleVolumeDrag, startDrag, volumeShow, handleVolumeClick, setVolumePercentage, volume, audioPlayer, playData, handleMouseleave, handleMouseenter, clickSongs, tags, tagsFill, containerFill, container };
},
}).mount("#song-request-station");