基础款:纯 HTML5 视频播放器

这个是最简单的实现,直接使用浏览器原生的 <video> 控件,几乎没有自定义样式,但它是所有自定义播放器的基础。

播放器代码网站网页html特效代码
(图片来源网络,侵删)

特点:

  • 零 JavaScript,纯 HTML。
  • 使用浏览器默认的播放控制条。
  • 兼容性最好。

代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">基础视频播放器</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: sans-serif;
        }
        video {
            max-width: 800px;
            width: 100%;
            border-radius: 8px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
        }
    </style>
</head>
<body>
    <video src="https://www.w3schools.com/html/mov_bbb.mp4" controls></video>
</body>
</html>

进阶款:自定义样式的视频播放器

这个例子隐藏了原生控件,并用 HTML/CSS/JS 创建了一个自定义的、美观的控制条。

特点:

播放器代码网站网页html特效代码
(图片来源网络,侵删)
  • 完全自定义的控制条样式(播放/暂停、进度条、音量、全屏)。
  • 鼠标悬停时显示控制条,实现“无干扰”播放体验。
  • 使用了 Font Awesome 图标库。

代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">自定义视频播放器</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: #222;
            font-family: Arial, sans-serif;
        }
        .video-container {
            position: relative;
            max-width: 900px;
            width: 100%;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 10px 25px rgba(0,0,0,0.5);
        }
        video {
            width: 100%;
            display: block;
            /* 隐藏原生控件 */
            display: block;
        }
        /* 自定义控制条 */
        .custom-controls {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
            padding: 20px;
            opacity: 0;
            transition: opacity 0.3s ease;
            pointer-events: none; /* 初始状态下不接收鼠标事件 */
        }
        .video-container:hover .custom-controls,
        .custom-controls:hover {
            opacity: 1;
            pointer-events: all; /* 鼠标悬停时接收事件 */
        }
        /* 进度条 */
        .progress-container {
            width: 100%;
            height: 6px;
            background: rgba(255,255,255,0.3);
            border-radius: 3px;
            cursor: pointer;
            margin-bottom: 10px;
        }
        .progress-bar {
            height: 100%;
            background: #e50914;
            border-radius: 3px;
            width: 0%;
            transition: width 0.1s linear;
        }
        /* 控制按钮组 */
        .controls {
            display: flex;
            align-items: center;
            gap: 15px;
        }
        button {
            background: none;
            border: none;
            color: white;
            cursor: pointer;
            font-size: 16px;
            outline: none;
        }
        .time-display {
            color: white;
            font-size: 12px;
            margin-left: 10px;
            flex-grow: 1;
        }
        .volume-slider {
            width: 80px;
            height: 4px;
            -webkit-appearance: none;
            appearance: none;
            background: rgba(255,255,255,0.3);
            outline: none;
            opacity: 0.7;
            transition: opacity 0.2s;
            border-radius: 2px;
        }
        .volume-slider:hover {
            opacity: 1;
        }
        .volume-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 12px;
            height: 12px;
            background: #e50914;
            cursor: pointer;
            border-radius: 50%;
        }
    </style>
</head>
<body>
    <div class="video-container">
        <video id="myVideo">
            <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
            您的浏览器不支持 HTML5 视频。
        </video>
        <div class="custom-controls">
            <div class="progress-container" id="progressContainer">
                <div class="progress-bar" id="progressBar"></div>
            </div>
            <div class="controls">
                <button id="playPauseBtn"><i class="fas fa-play"></i></button>
                <button id="muteBtn"><i class="fas fa-volume-up"></i></button>
                <input type="range" class="volume-slider" id="volumeSlider" min="0" max="1" step="0.1" value="1">
                <span class="time-display" id="timeDisplay">00:00 / 00:00</span>
                <button id="fullscreenBtn"><i class="fas fa-expand"></i></button>
            </div>
        </div>
    </div>
    <script>
        const video = document.getElementById('myVideo');
        const playPauseBtn = document.getElementById('playPauseBtn');
        const muteBtn = document.getElementById('muteBtn');
        const volumeSlider = document.getElementById('volumeSlider');
        const fullscreenBtn = document.getElementById('fullscreenBtn');
        const progressBar = document.getElementById('progressBar');
        const progressContainer = document.getElementById('progressContainer');
        const timeDisplay = document.getElementById('timeDisplay');
        // 播放/暂停
        playPauseBtn.addEventListener('click', togglePlayPause);
        function togglePlayPause() {
            if (video.paused) {
                video.play();
                playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>';
            } else {
                video.pause();
                playPauseBtn.innerHTML = '<i class="fas fa-play"></i>';
            }
        }
        // 静音/取消静音
        muteBtn.addEventListener('click', toggleMute);
        function toggleMute() {
            video.muted = !video.muted;
            if (video.muted) {
                muteBtn.innerHTML = '<i class="fas fa-volume-mute"></i>';
                volumeSlider.value = 0;
            } else {
                muteBtn.innerHTML = '<i class="fas fa-volume-up"></i>';
                volumeSlider.value = video.volume;
            }
        }
        // 调整音量
        volumeSlider.addEventListener('input', () => {
            video.volume = volumeSlider.value;
            if (video.volume > 0) {
                video.muted = false;
                muteBtn.innerHTML = '<i class="fas fa-volume-up"></i>';
            } else {
                video.muted = true;
                muteBtn.innerHTML = '<i class="fas fa-volume-mute"></i>';
            }
        });
        // 全屏
        fullscreenBtn.addEventListener('click', toggleFullscreen);
        function toggleFullscreen() {
            if (!document.fullscreenElement) {
                video.requestFullscreen().catch(err => {
                    alert(`Error attempting to enable fullscreen: ${err.message}`);
                });
                fullscreenBtn.innerHTML = '<i class="fas fa-compress"></i>';
            } else {
                document.exitFullscreen();
                fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i>';
            }
        }
        // 更新进度条
        video.addEventListener('timeupdate', updateProgress);
        function updateProgress() {
            const { currentTime, duration } = video;
            const progressPercent = (currentTime / duration) * 100;
            progressBar.style.width = `${progressPercent}%`;
            // 更新时间显示
            const currentMinutes = Math.floor(currentTime / 60);
            const currentSeconds = Math.floor(currentTime % 60).toString().padStart(2, '0');
            const durationMinutes = Math.floor(duration / 60);
            const durationSeconds = Math.floor(duration % 60).toString().padStart(2, '0');
            timeDisplay.textContent = `${currentMinutes}:${currentSeconds} / ${durationMinutes}:${durationSeconds}`;
        }
        // 点击进度条跳转
        progressContainer.addEventListener('click', setProgress);
        function setProgress(e) {
            const width = this.clientWidth;
            const clickX = e.offsetX;
            const duration = video.duration;
            video.currentTime = (clickX / width) * duration;
        }
    </script>
</body>
</html>

高级款:带歌词同步的音乐播放器

这个例子模拟了音乐播放器,并实现了一个酷炫的歌词同步滚动特效。

特点:

  • 歌词同步:歌词会根据当前播放时间高亮并滚动到中央。
  • 波形可视化:使用 Canvas 绘制音频波形图,增加视觉效果。
  • 自定义控件:播放、暂停、上一首、下一首、进度条。
  • 歌词数据:使用简单的 LRC 格式(需手动创建)。

代码结构: 由于代码较长,建议您创建三个文件:index.html, style.css, script.js

播放器代码网站网页html特效代码
(图片来源网络,侵删)

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">带歌词的音乐播放器</title>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
    <div class="player-container">
        <div class="player-header">
            <div class="now-playing">正在播放</div>
            <div class="track-info">
                <div class="track-name">示例歌曲</div>
                <div class="track-artist">示例歌手</div>
            </div>
        </div>
        <div class="visualizer-container">
            <canvas id="visualizer"></canvas>
        </div>
        <div class="lyrics-container" id="lyricsContainer">
            <!-- 歌词将通过 JS 动态插入 -->
        </div>
        <div class="progress-container">
            <span class="current-time">0:00</span>
            <div class="progress-bar" id="progressBar">
                <div class="progress" id="progress"></div>
            </div>
            <span class="duration">3:30</span>
        </div>
        <div class="controls">
            <button class="control-btn" id="prevBtn"><i class="fas fa-step-backward"></i></button>
            <button class="control-btn main-btn" id="playPauseBtn"><i class="fas fa-play"></i></button>
            <button class="control-btn" id="nextBtn"><i class="fas fa-step-forward"></i></button>
        </div>
    </div>
    <!-- 音频文件 -->
    <audio id="audioPlayer"></audio>
    <script src="script.js"></script>
</body>
</html>

style.css

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body {
    font-family: 'Noto Sans SC', sans-serif;
    background: linear-gradient(135deg, #1e3c72, #2a5298);
    color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}
.player-container {
    width: 90%;
    max-width: 450px;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    border-radius: 20px;
    padding: 30px;
    box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
    border: 1px solid rgba(255, 255, 255, 0.18);
}
.player-header {
    text-align: center;
    margin-bottom: 20px;
}
.now-playing {
    font-size: 12px;
    color: #aaa;
    text-transform: uppercase;
    letter-spacing: 2px;
}
.track-info {
    margin-top: 10px;
}
.track-name {
    font-size: 28px;
    font-weight: 700;
}
.track-artist {
    font-size: 18px;
    color: #aaa;
    margin-top: 5px;
}
.visualizer-container {
    width: 100%;
    height: 100px;
    margin: 20px 0;
    display: flex;
    justify-content: center;
    align-items: center;
}
#visualizer {
    width: 100%;
    height: 100%;
    border-radius: 10px;
}
.lyrics-container {
    height: 180px;
    overflow: hidden;
    position: relative;
    text-align: center;
    margin: 20px 0;
}
.lyrics-line {
    font-size: 16px;
    color: rgba(255, 255, 255, 0.5);
    padding: 5px 0;
    transition: all 0.3s ease;
    cursor: default;
}
.lyrics-line.active {
    color: #fff;
    font-size: 20px;
    font-weight: 500;
    transform: scale(1.1);
}
.progress-container {
    display: flex;
    align-items: center;
    gap: 15px;
    margin-bottom: 20px;
}
.current-time, .duration {
    font-size: 12px;
    color: #aaa;
}
.progress-bar {
    flex-grow: 1;
    height: 4px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 2px;
    cursor: pointer;
    position: relative;
}
.progress {
    height: 100%;
    background: #fff;
    border-radius: 2px;
    width: 0%;
    transition: width 0.1s linear;
}
.controls {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 20px;
}
.control-btn {
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    font-size: 20px;
    transition: transform 0.2s;
}
.control-btn:hover {
    transform: scale(1.1);
}
.main-btn {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 24px;
}
.main-btn:hover {
    background: rgba(255, 255, 255, 0.3);
}

script.js

document.addEventListener('DOMContentLoaded', () => {
    const audioPlayer = document.getElementById('audioPlayer');
    const playPauseBtn = document.getElementById('playPauseBtn');
    const prevBtn = document.getElementById('prevBtn');
    const nextBtn = document.getElementById('nextBtn');
    const progressBar = document.getElementById('progress');
    const progressContainer = document.getElementById('progressBar');
    const currentTimeEl = document.querySelector('.current-time');
    const durationEl = document.querySelector('.duration');
    const lyricsContainer = document.getElementById('lyricsContainer');
    const visualizer = document.getElementById('visualizer');
    const visualizerCtx = visualizer.getContext('2d');
    // --- 配置 ---
    // 使用一个在线的示例音频文件,并确保它支持 CORS
    const audioSrc = 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3'; 
    audioPlayer.src = audioSrc;
    // LRC 格式歌词 (时间标签 [mm:ss.xx] 或 [mm:ss])
    // 注意:这里的歌词是手动创建的,与示例音频无关,仅为演示同步效果。
    const lrcText = `
        [00:10.00]欢迎来到这个音乐世界
        [00:15.50]让旋律带你飞翔
        [00:21.00]没有烦恼
        [00:26.50]只有快乐和梦想
        [00:32.00]闭上你的眼睛
        [00:37.50]感受这心跳的节奏
        [00:43.00]让我们一起高歌
        [00:48.50]唱出心中的激昂
        [00:54.00]这是我们的歌
        [00:59.50]属于你和我
        [01:05.00]无论何时何地
        [01:10.50]音乐都在身旁
        [01:16.00]啦啦啦啦啦
        [01:21.50]啦啦啦啦啦
        [01:27.00]这是我们的歌
        [01:32.50]啦啦啦啦啦
        [01:38.00]啦啦啦啦啦
        [01:43.50]唱出心中的激昂
        [01:49.00]...
        [02:10.00]重复的副歌
        [02:15.50]让记忆更加深刻
        [02:21.00]每一个音符
        [02:26.50]都承载着一份情感
        [02:32.00]感谢你的聆听
        [02:37.50]希望你喜欢这首歌
    `;
    // --- 歌词解析 ---
    const lyrics = parseLrc(lrcText);
    renderLyrics();
    // --- 播放器功能 ---
    function togglePlayPause() {
        if (audioPlayer.paused) {
            audioPlayer.play();
            playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>';
            startVisualization();
        } else {
            audioPlayer.pause();
            playPauseBtn.innerHTML = '<i class="fas fa-play"></i>';
            stopVisualization();
        }
    }
    playPauseBtn.addEventListener('click', togglePlayPause);
    // 更新进度条和时间
    audioPlayer.addEventListener('timeupdate', () => {
        const { currentTime, duration } = audioPlayer;
        if (!isNaN(duration)) {
            const progressPercent = (currentTime / duration) * 100;
            progressBar.style.width = `${progressPercent}%`;
            currentTimeEl.textContent = formatTime(currentTime);
            durationEl.textContent = formatTime(duration);
        }
        updateLyrics(currentTime);
    });
    // 点击进度条跳转
    progressContainer.addEventListener('click', (e) => {
        const width = progressContainer.clientWidth;
        const clickX = e.offsetX;
        const duration = audioPlayer.duration;
        audioPlayer.currentTime = (clickX / width) * duration;
    });
    // 上一首/下一首 (示例中为同一首歌)
    prevBtn.addEventListener('click', () => { audioPlayer.currentTime = 0; });
    nextBtn.addEventListener('click', () => { audioPlayer.currentTime = 0; });
    // --- 辅助函数 ---
    function parseLrc(text) {
        const lines = text.trim().split('\n');
        const result = [];
        const regex = /\[(\d{2}):(\d{2})\.?(\d{0,2})\](.*)/;
        for (const line of lines) {
            const match = line.match(regex);
            if (match) {
                const minutes = parseInt(match[1]);
                const seconds = parseInt(match[2]);
                const milliseconds = match[3] ? parseInt(match[3]) : 0;
                const time = minutes * 60 + seconds + milliseconds / 100;
                result.push({ time, text: match[4].trim() });
            }
        }
        return result.sort((a, b) => a.time - b.time);
    }
    function renderLyrics() {
        lyricsContainer.innerHTML = '';
        lyrics.forEach(line => {
            const div = document.createElement('div');
            div.className = 'lyrics-line';
            div.textContent = line.text;
            div.dataset.time = line.time;
            lyricsContainer.appendChild(div);
        });
    }
    function updateLyrics(currentTime) {
        const lines = lyricsContainer.querySelectorAll('.lyrics-line');
        let activeLine = null;
        for (let i = 0; i < lines.length; i++) {
            if (currentTime >= parseFloat(lines[i].dataset.time)) {
                activeLine = lines[i];
            } else {
                break;
            }
        }
        lines.forEach(line => line.classList.remove('active'));
        if (activeLine) {
            activeLine.classList.add('active');
            // 滚动到可视区域中央
            const containerHeight = lyricsContainer.clientHeight;
            const lineHeight = activeLine.offsetHeight;
            const offset = activeLine.offsetTop - containerHeight / 2 + lineHeight / 2;
            lyricsContainer.scrollTo({ top: offset, behavior: 'smooth' });
        }
    }
    function formatTime(seconds) {
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        return `${mins}:${secs.toString().padStart(2, '0')}`;
    }
    // --- 音频可视化 ---
    let animationId;
    function startVisualization() {
        const bufferLength = 128;
        const dataArray = new Uint8Array(bufferLength);
        function draw() {
            animationId = requestAnimationFrame(draw);
            visualizerCtx.fillStyle = 'rgba(0, 0, 0, 0.1)';
            visualizerCtx.fillRect(0, 0, visualizer.width, visualizer.height);
            // 注意:Web Audio API 需要用户交互后才能初始化
            // 这里为了简化,我们使用一个模拟的动画
            // 实际项目中,你需要使用 audioContext.createAnalyser() 来获取真实数据
            for (let i = 0; i < bufferLength; i++) {
                const barHeight = Math.random() * visualizer.height * 0.7;
                const barWidth = (visualizer.width / bufferLength) * 2.5;
                const x = i * (barWidth + 1);
                const y = visualizer.height - barHeight;
                const gradient = visualizerCtx.createLinearGradient(0, y, 0, visualizer.height);
                gradient.addColorStop(0, '#fff');
                gradient.addColorStop(1, 'rgba(255,255,255,0.1)');
                visualizerCtx.fillStyle = gradient;
                visualizerCtx.fillRect(x, y, barWidth, barHeight);
            }
        }
        draw();
    }
    function stopVisualization() {
        if (animationId) {
            cancelAnimationFrame(animationId);
            visualizerCtx.clearRect(0, 0, visualizer.width, visualizer.height);
        }
    }
    // 初始化 Canvas 尺寸
    function resizeCanvas() {
        visualizer.width = visualizer.clientWidth;
        visualizer.height = visualizer.clientHeight;
    }
    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();
});

如何使用和修改

  1. 保存文件:将上述代码分别保存为 .html, .css, .js 文件,并放在同一个文件夹下。
  2. 替换资源
    • 进阶款 中,将 src="https://www.w3schools.com/html/mov_bbb.mp4" 替换成你自己的视频文件路径。
    • 高级款 中,将 audioSrc 替换成你自己的音乐文件路径(确保支持 CORS,否则可能无法播放),你可以修改 lrcText 中的歌词和时间,使其与你的音乐匹配。
  3. 部署:你可以直接在浏览器中打开 index.html 文件查看效果,或者使用任何本地服务器(如 VS Code 的 Live Server 插件)来运行,以避免可能的跨域问题。

这些代码示例为您提供了从简单到复杂的完整实现,希望能帮助您在项目中实现出色的播放器特效!