
html
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>音乐播放器 - 自定义字体与阴影</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
background: #000;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: white;
}
.container {
position: relative;
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 2rem;
background: #000;
}
.song-title-container {
text-align: center;
margin-top: 2rem;
z-index: 2;
}
.song-title {
font-size: 5rem;
font-weight: bold;
color: white;
margin-bottom: 1rem;
transition: all 0.5s ease;
line-height: 1.1;
}
.artist-name {
font-size: 1.5rem;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 2rem;
}
.controls {
display: flex;
justify-content: center;
gap: 1.5rem;
margin-top: 2rem;
flex-wrap: wrap;
z-index: 2;
}
button {
padding: 0.8rem 1.5rem;
border: none;
border-radius: 50px;
background: rgba(255, 255, 255, 0.2);
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(5px);
display: flex;
align-items: center;
gap: 0.5rem;
}
button:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-3px);
}
.file-input-container {
position: relative;
overflow: hidden;
display: inline-block;
}
.file-input-container input[type="file"] {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.customization-panel {
position: absolute;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.7);
padding: 1.5rem;
border-radius: 15px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
z-index: 3;
width: 300px;
}
.customization-panel h3 {
margin-bottom: 1rem;
font-size: 1.2rem;
color: white;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding-bottom: 0.5rem;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.8);
}
.form-control {
width: 100%;
padding: 0.5rem;
border-radius: 5px;
border: 1px solid rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.1);
color: white;
}
.color-input-container {
display: flex;
align-items: center;
gap: 10px;
}
.color-input {
width: 40px;
height: 40px;
border: none;
border-radius: 5px;
cursor: pointer;
background: transparent;
}
.color-input::-webkit-color-swatch {
border-radius: 5px;
border: none;
}
.color-input::-moz-color-swatch {
border-radius: 5px;
border: none;
}
.progress-container {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
overflow: hidden;
margin: 2rem 0;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #ff6b6b, #ffa500);
transition: width 0.3s ease;
}
.time-display {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 1rem;
}
.music-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
}
.music-controls button {
padding: 0.8rem;
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.play-pause-btn {
width: 60px !important;
height: 60px !important;
background: rgba(255, 255, 255, 0.3) !important;
}
.toggle-customization {
position: absolute;
top: 20px;
left: 20px;
z-index: 4;
}
.visualization {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 150px;
z-index: 1;
opacity: 0.5;
}
.visual-bar {
position: absolute;
bottom: 0;
width: 8px;
background: linear-gradient(to top, #ff6b6b, #ffa500);
border-radius: 4px 4px 0 0;
transition: height 0.1s ease;
}
.lyrics-display {
margin-top: 2rem;
text-align: center;
max-height: 200px;
overflow-y: auto;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
}
.lyrics-line {
margin-bottom: 0.5rem;
font-size: 1.1rem;
color: rgba(255, 255, 255, 0.8);
transition: all 0.3s ease;
}
.lyrics-line.active {
color: #ffa500;
font-weight: bold;
font-size: 1.3rem;
}
@keyframes pulse {
0% { opacity: 0.5; }
50% { opacity: 0.8; }
100% { opacity: 0.5; }
}
@keyframes glow {
0% { text-shadow: 0 0 10px currentColor; }
50% { text-shadow: 0 0 20px currentColor, 0 0 30px currentColor; }
100% { text-shadow: 0 0 10px currentColor; }
}
.glow {
animation: glow 2s infinite;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<button class="toggle-customization" id="toggleCustomization">
<i class="bi bi-palette"></i> 自定义
</button>
<div class="customization-panel" id="customizationPanel">
<h3>自定义设置</h3>
<div class="form-group">
<label for="songTitleInput">歌曲标题</label>
<input type="text" id="songTitleInput" class="form-control" value="夜的第七章" placeholder="输入歌曲标题">
</div>
<div class="form-group">
<label for="artistInput">歌手名称</label>
<input type="text" id="artistInput" class="form-control" value="周杰伦" placeholder="输入歌手名称">
</div>
<div class="form-group">
<label for="fontUpload">上传字体</label>
<div class="file-input-container">
<button class="form-control" style="text-align: left;">
<i class="bi bi-fonts"></i> 选择字体文件
</button>
<input type="file" id="fontUpload" accept=".ttf,.otf,.woff,.woff2">
</div>
</div>
<div class="form-group">
<label for="fontSize">字体大小</label>
<input type="range" id="fontSize" class="form-control" min="2" max="8" step="0.1" value="5">
<div style="color: rgba(255,255,255,0.6); font-size: 0.8rem; text-align: center; margin-top: 5px;">
<span id="fontSizeValue">5rem</span>
</div>
</div>
<div class="form-group">
<label>字体颜色</label>
<div class="color-input-container">
<input type="color" id="fontColor" class="color-input" value="#ffffff">
<span id="fontColorValue">#FFFFFF</span>
</div>
</div>
<div class="form-group">
<label>阴影颜色</label>
<div class="color-input-container">
<input type="color" id="shadowColor" class="color-input" value="#ff6b6b">
<span id="shadowColorValue">#FF6B6B</span>
</div>
</div>
<div class="form-group">
<label for="shadowBlur">阴影模糊度</label>
<input type="range" id="shadowBlur" class="form-control" min="0" max="20" value="10">
<div style="color: rgba(255,255,255,0.6); font-size: 0.8rem; text-align: center; margin-top: 5px;">
<span id="shadowBlurValue">10px</span>
</div>
</div>
<button id="applySettings" class="form-control" style="background: rgba(255,107,107,0.7); margin-top: 1rem;">
<i class="bi bi-check-lg"></i> 应用设置
</button>
</div>
<div class="song-title-container">
<div class="song-title" id="songTitle">夜的第七章</div>
<div class="artist-name" id="artistName">周杰伦</div>
</div>
<div class="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="time-display">
<span id="currentTime">0:00</span>
<span id="totalTime">0:00</span>
</div>
<div class="music-controls">
<button id="prevBtn"><i class="bi bi-skip-start-fill"></i></button>
<button id="playBtn" class="play-pause-btn"><i class="bi bi-play-fill"></i></button>
<button id="nextBtn"><i class="bi bi-skip-end-fill"></i></button>
</div>
<div class="controls">
<div class="file-input-container">
<button id="musicUploadBtn"><i class="bi bi-music-note-beamed"></i> 上传歌曲</button>
<input type="file" id="musicUpload" accept="audio/*">
</div>
<div class="file-input-container">
<button id="lyricsUploadBtn"><i class="bi bi-file-text"></i> 上传歌词</button>
<input type="file" id="lyricsUpload" accept=".lrc,.txt">
</div>
<button id="toggleVisualization"><i class="bi bi-soundwave"></i> 可视化效果</button>
<button id="toggleGlow"><i class="bi bi-stars"></i> 发光效果</button>
</div>
<div class="lyrics-display" id="lyricsDisplay">
<div class="lyrics-line">请上传歌词文件</div>
</div>
<div class="visualization" id="visualization"></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 获取DOM元素
const songTitle = document.getElementById('songTitle');
const artistName = document.getElementById('artistName');
const songTitleInput = document.getElementById('songTitleInput');
const artistInput = document.getElementById('artistInput');
const fontSize = document.getElementById('fontSize');
const fontSizeValue = document.getElementById('fontSizeValue');
const fontColor = document.getElementById('fontColor');
const fontColorValue = document.getElementById('fontColorValue');
const shadowColor = document.getElementById('shadowColor');
const shadowColorValue = document.getElementById('shadowColorValue');
const shadowBlur = document.getElementById('shadowBlur');
const shadowBlurValue = document.getElementById('shadowBlurValue');
const fontUpload = document.getElementById('fontUpload');
const applySettings = document.getElementById('applySettings');
const toggleCustomization = document.getElementById('toggleCustomization');
const customizationPanel = document.getElementById('customizationPanel');
const musicUpload = document.getElementById('musicUpload');
const musicUploadBtn = document.getElementById('musicUploadBtn');
const lyricsUpload = document.getElementById('lyricsUpload');
const lyricsUploadBtn = document.getElementById('lyricsUploadBtn');
const lyricsDisplay = document.getElementById('lyricsDisplay');
const playBtn = document.getElementById('playBtn');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const progressBar = document.getElementById('progressBar');
const currentTime = document.getElementById('currentTime');
const totalTime = document.getElementById('totalTime');
const toggleVisualization = document.getElementById('toggleVisualization');
const visualization = document.getElementById('visualization');
const toggleGlow = document.getElementById('toggleGlow');
let audioElement = null;
let isPlaying = false;
let isVisualizationVisible = true;
let isGlowEnabled = false;
let customFont = null;
let lyricsData = [];
let currentLyricIndex = 0;
// 初始化设置
function initSettings() {
// 设置字体大小
fontSizeValue.textContent = `${fontSize.value}rem`;
songTitle.style.fontSize = `${fontSize.value}rem`;
// 设置字体颜色
fontColorValue.textContent = fontColor.value.toUpperCase();
songTitle.style.color = fontColor.value;
// 设置阴影
updateTextShadow();
// 应用歌曲标题和歌手名称
songTitle.textContent = songTitleInput.value;
artistName.textContent = artistInput.value;
}
// 更新文本阴影
function updateTextShadow() {
const blur = `${shadowBlur.value}px`;
const color = shadowColor.value;
shadowBlurValue.textContent = `${shadowBlur.value}px`;
shadowColorValue.textContent = color.toUpperCase();
songTitle.style.textShadow = `0 0 ${blur} ${color}`;
artistName.style.textShadow = `0 0 ${blur} ${color}`;
}
// 应用设置
applySettings.addEventListener('click', () => {
initSettings();
// 显示成功提示
const originalText = applySettings.innerHTML;
applySettings.innerHTML = '<i class="bi bi-check-lg"></i> 已应用';
applySettings.style.background = 'rgba(76, 175, 80, 0.7)';
setTimeout(() => {
applySettings.innerHTML = originalText;
applySettings.style.background = 'rgba(255,107,107,0.7)';
}, 2000);
});
// 切换自定义面板
toggleCustomization.addEventListener('click', () => {
customizationPanel.classList.toggle('hidden');
});
// 字体大小变化
fontSize.addEventListener('input', () => {
fontSizeValue.textContent = `${fontSize.value}rem`;
songTitle.style.fontSize = `${fontSize.value}rem`;
});
// 字体颜色变化
fontColor.addEventListener('input', () => {
fontColorValue.textContent = fontColor.value.toUpperCase();
songTitle.style.color = fontColor.value;
});
// 阴影颜色变化
shadowColor.addEventListener('input', () => {
updateTextShadow();
});
// 阴影模糊度变化
shadowBlur.addEventListener('input', () => {
updateTextShadow();
});
// 上传字体
fontUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const fontUrl = URL.createObjectURL(file);
customFont = new FontFace('CustomFont', `url(${fontUrl})`);
customFont.load().then((loadedFont) => {
document.fonts.add(loadedFont);
songTitle.style.fontFamily = 'CustomFont, sans-serif';
artistName.style.fontFamily = 'CustomFont, sans-serif';
// 显示成功提示
musicUploadBtn.innerHTML = `<i class="bi bi-fonts"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
}).catch((error) => {
console.error('字体加载失败:', error);
alert('字体加载失败,请尝试其他字体文件。');
});
}
});
// 上传歌词
lyricsUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const content = event.target.result;
parseLyrics(content);
displayLyrics();
// 更新按钮文本
lyricsUploadBtn.innerHTML = `<i class="bi bi-file-text"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
};
reader.readAsText(file);
}
});
// 解析歌词
function parseLyrics(content) {
lyricsData = [];
const lines = content.split('\n');
for (let line of lines) {
line = line.trim();
if (!line) continue;
// 尝试解析LRC格式
const timeMatch = line.match(/\[(\d+):(\d+\.\d+)\](.*)/);
if (timeMatch) {
const minutes = parseInt(timeMatch[1]);
const seconds = parseFloat(timeMatch[2]);
const text = timeMatch[3].trim();
const time = minutes * 60 + seconds;
lyricsData.push({
time: time,
text: text
});
} else if (line.startsWith('[') && line.includes('ti:')) {
// 提取歌曲标题
const titleMatch = line.match(/\[ti:(.*)\]/);
if (titleMatch) {
songTitleInput.value = titleMatch[1].trim();
songTitle.textContent = titleMatch[1].trim();
}
} else if (line.startsWith('[') && line.includes('ar:')) {
// 提取歌手名称
const artistMatch = line.match(/\[ar:(.*)\]/);
if (artistMatch) {
artistInput.value = artistMatch[1].trim();
artistName.textContent = artistMatch[1].trim();
}
} else {
// 普通文本行
lyricsData.push({
time: null,
text: line
});
}
}
// 按时间排序
lyricsData.sort((a, b) => {
if (a.time === null) return 1;
if (b.time === null) return -1;
return a.time - b.time;
});
}
// 显示歌词
function displayLyrics() {
lyricsDisplay.innerHTML = '';
if (lyricsData.length === 0) {
lyricsDisplay.innerHTML = '<div class="lyrics-line">没有找到歌词</div>';
return;
}
lyricsData.forEach((lyric, index) => {
const line = document.createElement('div');
line.className = 'lyrics-line';
line.textContent = lyric.text;
line.dataset.index = index;
lyricsDisplay.appendChild(line);
});
}
// 更新当前歌词
function updateCurrentLyric() {
if (!audioElement || lyricsData.length === 0) return;
const currentTime = audioElement.currentTime;
let newIndex = 0;
// 找到当前时间对应的歌词
for (let i = 0; i < lyricsData.length; i++) {
if (lyricsData[i].time !== null && lyricsData[i].time <= currentTime) {
newIndex = i;
} else {
break;
}
}
// 更新高亮
if (newIndex !== currentLyricIndex) {
const oldLine = lyricsDisplay.querySelector('.lyrics-line.active');
if (oldLine) {
oldLine.classList.remove('active');
}
const newLine = lyricsDisplay.querySelector(`.lyrics-line[data-index="${newIndex}"]`);
if (newLine) {
newLine.classList.add('active');
// 滚动到当前歌词
newLine.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
currentLyricIndex = newIndex;
}
}
// 上传音乐
musicUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
if (audioElement) {
audioElement.pause();
}
const url = URL.createObjectURL(file);
audioElement = new Audio(url);
// 更新按钮文本
musicUploadBtn.innerHTML = `<i class="bi bi-music-note-beamed"></i> ${file.name.substring(0, 10)}${file.name.length > 10 ? '...' : ''}`;
// 设置音频事件
audioElement.addEventListener('loadedmetadata', () => {
totalTime.textContent = formatTime(audioElement.duration);
});
audioElement.addEventListener('timeupdate', () => {
const progress = (audioElement.currentTime / audioElement.duration) * 100;
progressBar.style.width = `${progress}%`;
currentTime.textContent = formatTime(audioElement.currentTime);
// 更新歌词
updateCurrentLyric();
});
audioElement.addEventListener('ended', () => {
isPlaying = false;
playBtn.innerHTML = '<i class="bi bi-play-fill"></i>';
progressBar.style.width = '0%';
currentTime.textContent = '0:00';
});
// 自动播放
audioElement.play().then(() => {
isPlaying = true;
playBtn.innerHTML = '<i class="bi bi-pause-fill"></i>';
}).catch(error => {
console.error('播放错误:', error);
});
}
});
// 播放/暂停
playBtn.addEventListener('click', () => {
if (audioElement) {
if (isPlaying) {
audioElement.pause();
isPlaying = false;
playBtn.innerHTML = '<i class="bi bi-play-fill"></i>';
} else {
audioElement.play().then(() => {
isPlaying = true;
playBtn.innerHTML = '<i class="bi bi-pause-fill"></i>';
}).catch(error => {
console.error('播放错误:', error);
});
}
}
});
// 上一曲/下一曲(示例功能)
prevBtn.addEventListener('click', () => {
if (audioElement) {
audioElement.currentTime = Math.max(0, audioElement.currentTime - 10);
}
});
nextBtn.addEventListener('click', () => {
if (audioElement) {
audioElement.currentTime = Math.min(audioElement.duration, audioElement.currentTime + 10);
}
});
// 切换可视化效果
toggleVisualization.addEventListener('click', () => {
isVisualizationVisible = !isVisualizationVisible;
visualization.style.opacity = isVisualizationVisible ? '0.5' : '0';
toggleVisualization.innerHTML = isVisualizationVisible ?
'<i class="bi bi-soundwave"></i> 隐藏可视化' :
'<i class="bi bi-soundwave"></i> 显示可视化';
});
// 切换发光效果
toggleGlow.addEventListener('click', () => {
isGlowEnabled = !isGlowEnabled;
if (isGlowEnabled) {
songTitle.classList.add('glow');
toggleGlow.innerHTML = '<i class="bi bi-stars"></i> 关闭发光';
toggleGlow.style.background = 'rgba(255,107,107,0.7)';
} else {
songTitle.classList.remove('glow');
toggleGlow.innerHTML = '<i class="bi bi-stars"></i> 发光效果';
toggleGlow.style.background = 'rgba(255,255,255,0.2)';
}
});
// 创建可视化效果
function createVisualization() {
visualization.innerHTML = '';
const barCount = 50;
const width = visualization.clientWidth / barCount;
for (let i = 0; i < barCount; i++) {
const bar = document.createElement('div');
bar.className = 'visual-bar';
bar.style.left = `${i * width}px`;
bar.style.width = `${width - 2}px`;
bar.style.height = `${Math.random() * 100 + 20}px`;
visualization.appendChild(bar);
}
// 动画效果
setInterval(() => {
if (isVisualizationVisible && isPlaying) {
const bars = document.querySelectorAll('.visual-bar');
bars.forEach(bar => {
const newHeight = Math.random() * 100 + 20;
bar.style.height = `${newHeight}px`;
});
}
}, 200);
}
// 格式化时间
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
}
// 初始化
initSettings();
createVisualization();
// 窗口大小变化时重新创建可视化
window.addEventListener('resize', createVisualization);
});
</script>
</body>
</html>