|
|
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>音乐播放器</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #fff;
min-height: 100vh;
font-family: sans-serif;
padding: 20px; /* 添加内边距,避免小屏幕时贴边 */
/* 移除了 display: flex,这可能是导致页面右移的原因 */
}
/* 外层容器:确保播放器始终居中 */
.player-wrapper {
width: 100%;
max-width: 1200px; /* 最大宽度限制 */
margin: 0 auto; /* 水平居中 */
}
#pa {
width: 100%; /* 宽度自适应父容器 */
height: 675px;
border: 1px solid #ddd;
display: grid;
place-items: center;
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.1);
/* 修复居中问题的关键:确保容器正常显示 */
}
/* 背景MP4层 */
#bg-video {
position: absolute;
top: 50%; /* 垂直居中 */
left: 50%; /* 水平居中 */
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.6;
z-index: 0;
transform: translate(-50%, -50%); /* 修正居中 */
}
/* 静态图片层 */
#bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('https://cccimg.com/view.php/8f7191d6c76360c65308a5b525b9f558.jpg');
background-size: cover;
background-position: center;
opacity: 0.8;
z-index: 1;
}
#wrapper {
position: absolute;
padding: 10px;
font: bold 2.5rem/1.5 sans-serif;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
bottom: 150px;
z-index: 10;
text-align: center;
width: 90%; /* 限制歌词宽度,避免溢出 */
max-width: 800px;
left: 50%;
transform: translateX(-50%); /* 水平居中 */
}
.char {
display: inline-block;
padding: 0 3px;
opacity: 0;
transform: translate(var(--x), var(--y));
animation: fadeIn 0.3s var(--delay) forwards;
transition: all 0.3s ease;
}
/* 隐藏原生音频控件 */
audio {
display: none;
}
/* 自定义播放器控制面板 */
.player-controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%); /* 精确水平居中 */
z-index: 20;
display: flex;
align-items: center;
gap: 15px; /* 调整间距,避免溢出 */
width: 95%; /* 宽度自适应 */
max-width: 800px;
padding: 0 10px;
}
.control-btn {
width: 60px;
height: 60px;
border-radius: 50%;
background-color: rgba(240, 240, 240, 0.8);
border: 2px solid rgba(100, 100, 100, 0.8);
color: #333;
font-size: 24px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(5px);
flex-shrink: 0; /* 防止按钮缩小 */
}
.control-btn:hover {
background-color: rgba(220, 220, 220, 0.8);
transform: scale(1.1);
}
.play-btn {
width: 70px;
height: 70px;
background-color: rgba(255, 105, 180, 0.8);
border-color: #ff4785;
color: white;
}
.play-btn:hover {
background-color: rgba(255, 105, 180, 1);
}
/* 进度条 */
.progress-container {
flex: 1;
height: 8px;
background-color: rgba(200, 200, 200, 0.5);
border-radius: 4px;
cursor: pointer;
position: relative;
min-width: 100px; /* 最小宽度,避免太小时消失 */
}
.progress-bar {
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: #ff69b4;
border-radius: 4px;
width: 0%;
transition: width 0.3s ease;
}
/* 时间显示 */
.time-display {
color: #333;
font-size: 14px;
min-width: 60px; /* 固定最小宽度,避免抖动 */
text-align: center;
flex-shrink: 0; /* 防止时间文字缩小 */
}
@keyframes fadeIn {
to {
transform: translate(0, 0);
opacity: 1;
}
}
/* 响应式调整:针对不同屏幕尺寸优化 */
@media (max-width: 1024px) {
#pa {
height: 550px; /* 中等屏幕减小高度 */
}
#wrapper {
font-size: 2.2rem;
bottom: 130px;
}
}
@media (max-width: 768px) {
#pa {
height: 480px; /* 平板屏幕进一步减小高度 */
}
#wrapper {
font-size: 1.8rem;
bottom: 110px;
}
.player-controls {
gap: 10px;
}
.control-btn {
width: 45px;
height: 45px;
font-size: 18px;
}
.play-btn {
width: 55px;
height: 55px;
}
.time-display {
font-size: 12px;
min-width: 50px;
}
}
@media (max-width: 480px) {
#pa {
height: 400px; /* 手机屏幕最小高度 */
}
#wrapper {
font-size: 1.5rem;
bottom: 90px;
}
.player-controls {
gap: 8px;
}
.control-btn {
width: 40px;
height: 40px;
font-size: 16px;
}
.play-btn {
width: 50px;
height: 50px;
}
}
</style>
</head>
<body>
<!-- 外层容器,确保整体居中 -->
<div class="player-wrapper">
<div id="pa">
<!-- 背景MP4层 -->
<video id="bg-video" loop muted playsinline>
<source src="https://cccimg.com/view.php/3ea54d6409ddc292d6b89500f016f96e.mp4" type="video/mp4">
您的浏览器不支持视频播放
</video>
<!-- 静态图片层 -->
<div id="bg-image"></div>
<!-- 音频元素 -->
<audio id="aud" src="https://cccimg.com/view.php/7404fa9c5e73097aefa645b90d63a7a2.mp3" autoplay></audio>
<!-- 歌词显示区 -->
<div id="wrapper">HUACHAO LRC</div>
<!-- 自定义播放器控制面板 -->
<div class="player-controls">
<div class="time-display" id="current-time">00:00</div>
<div class="progress-container" id="progress-container">
<div class="progress-bar" id="progress-bar"></div>
</div>
<div class="time-display" id="total-time">00:00</div>
<button class="control-btn" id="prev-btn">⏮</button>
<button class="control-btn play-btn" id="play-btn">⏸</button>
<button class="control-btn" id="next-btn">⏭</button>
</div>
</div>
</div>
<script>
const gc = `[00:00.0]终于把你遇见 - 徐子崴/罗姣
[00:03.18]词:徐子崴
[00:04.4]曲:徐子崴
[00:05.62]编曲:冯丹
[00:06.84]吉他:孙越
[00:08.07]萧:丁晓逵
[00:09.29]伴唱:凌菲
[00:10.51]录音:欧力
[00:11.74]录音棚:崴IP•MUSIC
[00:13.45]音频编辑 Audio Editor:刘璇
[00:15.65]混音工程师 Mixing Engineer:王路遥
[00:18.34]母带工程师 Mastering Engineer:王路遥
[00:21.03]录音/混音/母带棚:@2496 Top Music
[00:24.21]封面设计:李政
[00:25.92]出品:福唱音乐
[00:27.64]制作人:徐子崴
[00:29.35]如果一生有一百年
[00:35.75]不过是三万六千五百天
[00:42.19]我穿过河流啊我越过高山
[00:48.66]只为能和你见呀见一面
[00:55.18]如果一生有一百年
[01:01.7]说起来很长说来也很短
[01:08.24]我仰望日月啊我祈求上天
[01:14.64]只为能和你走呀走一段
[01:27.729996]多想把你遇见
[01:34.1]恰好在对的时间
[01:40.68]我愿用前世的苦难
[01:47.11]换与你今生的情缘
[01:53.44]终于把你遇见
[02:00.05]恰好在对的时间
[02:06.58]我愿以今生的相伴
[02:13.08]许和你来世的圆满
[02:45.52]如果一生有一百年
[02:51.95999]说起来很长说来也很短
[02:58.49]我仰望日月啊我祈求上天
[03:04.94]只为能和你走呀走一段
[03:14.75]多想把你遇见
[03:21.19]恰好在对的时间
[03:27.70999]我愿用前世的苦难
[03:34.16]换与你今生的情缘
[03:40.61]终于把你遇见
[03:47.07]恰好在对的时间
[03:53.67]我愿以今生的相伴
[04:00.08]许和你来世的圆满
[04:06.56]许和你来世的圆满`;
const gcAr = lrc2HC(gc);
let curkey = 0, isSeeking = false;
const aud = document.getElementById('aud');
const playBtn = document.getElementById('play-btn');
const progressBar = document.getElementById('progress-bar');
const progressContainer = document.getElementById('progress-container');
const currentTimeEl = document.getElementById('current-time');
const totalTimeEl = document.getElementById('total-time');
const bgVideo = document.getElementById('bg-video');
const wrapper = document.getElementById('wrapper'); // 添加这行,修复wrapper未定义的问题
// 初始化背景视频播放
window.addEventListener('load', () => {
bgVideo.play().catch(err => {
console.log('视频自动播放被阻止,用户交互后将播放:', err);
document.body.addEventListener('click', () => {
bgVideo.play();
}, { once: true });
});
});
// 音频时间更新事件
aud.ontimeupdate = () => {
updateProgress();
updateTimeDisplay();
if(curkey > gcAr.length - 1) return;
if(aud.currentTime >= gcAr[curkey][0] && !isSeeking) {
const nextTime = gcAr[curkey + 1]?.[0] || aud.duration;
const gap = nextTime - gcAr[curkey][0];
showLrc(gcAr[curkey][1], wrapper, gap);
}
};
// 音频结束事件
aud.onended = () => {
curkey = 0;
playBtn.textContent = '▶';
aud.play();
};
// 音频就绪后显示总时长
aud.onloadedmetadata = () => {
totalTimeEl.textContent = formatTime(aud.duration);
};
// 音频跳转后重新计算歌词位置
aud.onseeked = () => {
calcKey();
updateProgress();
};
// 播放/暂停按钮点击事件
playBtn.addEventListener('click', () => {
if(aud.paused) {
aud.play();
bgVideo.play();
playBtn.textContent = '⏸';
} else {
aud.pause();
bgVideo.pause();
playBtn.textContent = '▶';
}
});
// 进度条点击事件
progressContainer.addEventListener('click', (e) => {
const rect = progressContainer.getBoundingClientRect();
const pos = (e.clientX - rect.left) / rect.width;
aud.currentTime = pos * aud.duration;
isSeeking = true;
});
// 格式化时间为 MM:SS 格式
function formatTime(seconds) {
if(isNaN(seconds)) return '00:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
// 更新进度条
function updateProgress() {
const percent = (aud.currentTime / aud.duration) * 100;
progressBar.style.width = `${percent}%`;
}
// 更新时间显示
function updateTimeDisplay() {
currentTimeEl.textContent = formatTime(aud.currentTime);
}
// 歌词解析函数
function lrc2HC(text) {
let lrcAr = [];
let ar = text.trim().split('\n');
ar.sort();
let reg = /\[(\d+)[.:](\d+)[.:](\d+)\](.*)/;
ar.forEach(item => {
if(reg.test(item)) {
let result = item.match(reg);
let tmsg = parseInt(result[1]) * 60 + parseInt(result[2]) + parseInt(result[3]) / 1000;
lrcAr.push([tmsg, result[4].trim()]);
}
});
return lrcAr.length ? lrcAr : [[0, 'HUACHAO']];
}
// 计算当前应该显示的歌词索引
function calcKey() {
for (let j = 0; j < gcAr.length; j++) {
if (aud.currentTime <= gcAr[j][0]) {
curkey = j - 1;
break;
}
}
if (curkey < 0) curkey = 0;
if (curkey >= gcAr.length) curkey = gcAr.length - 1;
const nextTime = gcAr[curkey + 1]?.[0] || aud.duration;
const time = nextTime - gcAr[curkey][0];
isSeeking = false;
showLrc(gcAr[curkey][1], wrapper, time);
}
// 显示歌词
function showLrc(str, targetElm, time) {
if(isSeeking) return;
targetElm.innerHTML = '';
const chars = str.split('').map(c => c === ' ' ? ' ' : c);
const frg = document.createDocumentFragment();
chars.forEach((char, idx) => {
const span = document.createElement('span');
span.innerHTML = char;
span.classList.add('char');
const x = Math.random() * (Math.random() > 0.5 ? 300 : -300);
const y = Math.random() * (Math.random() > 0.5 ? 300 : -300);
const color = Math.floor(Math.random() * 0x666666 + 0x000000).toString(16).padStart(6, '0');
span.style.cssText += `
color: #${color};
--x: ${x}px;
--y: ${y}px;
--delay: ${Math.random() * 0.5}s;
`;
frg.appendChild(span);
});
targetElm.appendChild(frg);
curkey++;
setTimeout(() => isSeeking = false, time * 1000);
}
// 上一曲/下一曲功能
document.getElementById('prev-btn').addEventListener('click', () => {
aud.currentTime = Math.max(0, aud.currentTime - 10);
isSeeking = true;
});
document.getElementById('next-btn').addEventListener('click', () => {
aud.currentTime = Math.min(aud.duration, aud.currentTime + 10);
isSeeking = true;
});
</script>
</body>
|
|