Web前端网站(四)- 音乐播放器

简介: 【8月更文挑战第9天】页面整体色调背景采用柔和渐变的方式呈现,与主页面的“毒药水式”色彩搭配形成了强烈的对比;周边花瓣缓缓飘落到水面之上形成涟漪。整体给人一种温馨、浪漫的感觉,还可以通过中间的3个按钮来控制音乐的切换和播放效果。每一行代码都有详细注释~~~大家可以尽情创作

音乐播放器

开篇(请大家看完):此网站写给挚爱,后续页面还会慢慢更新,大家敬请期待~ ~ ~

此前端框架,主要侧重于前端页面的视觉效果和交互体验。通过运用各种前端技术和创意,精心打造了一系列引人入胜的页面特效,会为大家带来全新的浏览体验。

同时,我非常支持和鼓励大家对这个框架进行二次创作或修改。您可以根据自己的需求和喜好,对框架进行个性化的定制和扩展,以打造出更符合自己品味的页面效果。

但请注意,如果您打算将这个框架转发给其他人或用于其他场合,请务必注明原创来源。让我们一起维护一个良好的创作环境。

最后,轻舟会继续更新和完善这个前端页面特效框架,为大家带来更多有趣、实用的功能和效果。感谢您的支持和关注!

页面效果:整体色调背景采用柔和渐变的方式呈现,与主页面的“毒药水式”色彩搭配形成了强烈的对比;周边花瓣缓缓飘落到水面之上形成涟漪。整体给人一种温馨、浪漫的感觉,还可以通过中间的3个按钮来控制音乐的切换和播放
屏幕截图 2024-08-02 092125.png
屏幕截图 2024-08-02 092100.png

一:音乐播放.html

<!DOCTYPE HTML>  
<html>  
<head>  
    <title>音乐播放</title> <!-- 页面标题 -->  
    <meta name="Generator" content="EditPlus"> <!-- 生成器信息 -->  
    <meta name="Author" content=""> <!-- 作者信息 -->  
    <meta name="Keywords" content=""> <!-- 页面关键词 -->  
    <meta name="Description" content=""> <!-- 页面描述 -->  
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 视图窗口设置 -->  
    <meta charset="UTF-8"> <!-- 字符编码 -->  
    <link rel="stylesheet" href="CSS/音乐播放.css"> <!-- 引入样式表 -->  

    <script type="text/javascript" src="JS/jquery-3.7.1.min.js"></script> <!-- 引入jQuery库 -->  
</head>  

<body>  
    <div id="jsi-cherry-container" class="container"></div> <!-- 花瓣容器 -->  
    <script>  
        var RENDERER = {
    
      
            INIT_CHERRY_BLOSSOM_COUNT: 30, // 初始花瓣数量  
            MAX_ADDING_INTERVAL: 10, // 最大添加间隔  

            init: function () {
    
     // 初始化函数  
                this.setParameters();  
                this.reconstructMethods();  
                this.createCherries();  
                this.render();  
            },  
            setParameters: function () {
    
     // 设置参数  
                this.$container = $('#jsi-cherry-container');  
                this.width = this.$container.width();  
                this.height = this.$container.height();  
                this.context = $('<canvas />').attr({
    
     width: this.width, height: this.height }).appendTo(this.$container).get(0).getContext('2d');  
                this.cherries = [];  
                this.maxAddingInterval = Math.round(this.MAX_ADDING_INTERVAL * 1000 / this.width);  
                this.addingInterval = this.maxAddingInterval;  
            },  
            reconstructMethods: function () {
    
     // 重构方法  
                this.render = this.render.bind(this);  
            },  
            createCherries: function () {
    
     // 创建花瓣 
                for (var i = 0, length = Math.round(this.INIT_CHERRY_BLOSSOM_COUNT * this.width / 1000); i < length; i++) {
    
      
                    this.cherries.push(new CHERRY_BLOSSOM(this, true));  
                }  
            },  
            render: function () {
    
     // 渲染函数  
                requestAnimationFrame(this.render);  
                this.context.clearRect(0, 0, this.width, this.height);  

                this.cherries.sort(function (cherry1, cherry2) {
    
      
                    return cherry1.z - cherry2.z;  
                });  
                for (var i = this.cherries.length - 1; i >= 0; i--) {
    
      
                    if (!this.cherries[i].render(this.context)) {
    
      
                        this.cherries.splice(i, 1);  
                    }  
                }  
                if (--this.addingInterval == 0) {
    
      
                    this.addingInterval = this.maxAddingInterval;  
                    this.cherries.push(new CHERRY_BLOSSOM(this, false));  
                }  
            }  
        };  
        var CHERRY_BLOSSOM = function (renderer, isRandom) {
    
     // 花瓣构造函数  
            this.renderer = renderer;  
            this.init(isRandom);  
        };  
        CHERRY_BLOSSOM.prototype = {
    
      
            FOCUS_POSITION: 300, // 焦点位置  
            FAR_LIMIT: 600, // 远离限制  
            MAX_RIPPLE_COUNT: 100, // 最大波纹数量  
            RIPPLE_RADIUS: 100, // 波纹半径  
            SURFACE_RATE: 0.5, // 表面比率  
            SINK_OFFSET: 20, // 下沉偏移量  

            init: function (isRandom) {
    
     // 初始化  
                this.x = this.getRandomValue(-this.renderer.width, this.renderer.width);  
                this.y = isRandom ? this.getRandomValue(0, this.renderer.height) : this.renderer.height * 1.5;  
                this.z = this.getRandomValue(0, this.FAR_LIMIT);  
                this.vx = this.getRandomValue(-2, 2);  
                this.vy = -2;  
                this.theta = this.getRandomValue(0, Math.PI * 2);  
                this.phi = this.getRandomValue(0, Math.PI * 2);  
                this.psi = 0;  
                this.dpsi = this.getRandomValue(Math.PI / 600, Math.PI / 300);  
                this.opacity = 0;  
                this.endTheta = false;  
                this.endPhi = false;  
                this.rippleCount = 0;  

                var axis = this.getAxis(),  
                    theta = this.theta + Math.ceil(-(this.y + this.renderer.height * this.SURFACE_RATE) / this.vy) * Math.PI / 500;  
                theta %= Math.PI * 2;  

                this.offsetY = 40 * ((theta <= Math.PI / 2 || theta >= Math.PI * 3 / 2) ? -1 : 1);  
                this.thresholdY = this.renderer.height / 2 + this.renderer.height * this.SURFACE_RATE * axis.rate;  
                this.entityColor = this.renderer.context.createRadialGradient(0, 40, 0, 0, 40, 80);  
                this.entityColor.addColorStop(0, 'hsl(330, 70%, ' + 50 * (0.3 + axis.rate) + '%)');  
                this.entityColor.addColorStop(0.05, 'hsl(330, 40%,' + 55 * (0.3 + axis.rate) + '%)');  
                this.entityColor.addColorStop(1, 'hsl(330, 20%, ' + 70 * (0.3 + axis.rate) + '%)');  
                this.shadowColor = this.renderer.context.createRadialGradient(0, 40, 0, 0, 40, 80);  
                this.shadowColor.addColorStop(0, 'hsl(330, 40%, ' + 30 * (0.3 + axis.rate) + '%)');  
                this.shadowColor.addColorStop(0.05, 'hsl(330, 40%,' + 30 * (0.3 + axis.rate) + '%)');  
                this.shadowColor.addColorStop(1, 'hsl(330, 20%, ' + 40 * (0.3 + axis.rate) + '%)');  
            },  
            getRandomValue: function (min, max) {
    
     // 获取随机值  
                return min + (max - min) * Math.random();  
            },  
            getAxis: function () {
    
     // 获取轴  
                var rate = this.FOCUS_POSITION / (this.z + this.FOCUS_POSITION),  
                    x = this.renderer.width / 2 + this.x * rate,  
                    y = this.renderer.height / 2 - this.y * rate;  
                return {
    
     rate: rate, x: x, y: y };  
            },  
            renderCherry: function (context, axis) {
    
     // 渲染花瓣 
                context.beginPath();  
                context.moveTo(0, 40);  
                context.bezierCurveTo(-60, 20, -10, -60, 0, -20);  
                context.bezierCurveTo(10, -60, 60, 20, 0, 40);  
                context.fill();  

                for (var i = -4; i < 4; i++) {
    
      
                    context.beginPath();  
                    context.moveTo(0, 40);  
                    context.quadraticCurveTo(i * 12, 10, i * 4, -24 + Math.abs(i) * 2);  
                    context.stroke();  
                }  
            },  
            render: function (context) {
    
      
                var axis = this.getAxis(); // 获取某种轴或坐标信息  

                // 如果y坐标等于阈值且涟漪计数小于最大涟漪计数,则绘制涟漪效果  
                if (axis.y == this.thresholdY && this.rippleCount < this.MAX_RIPPLE_COUNT) {
    
      
                    context.save(); // 保存当前环境的状态  
                    context.lineWidth = 2; // 设置线宽  
                    // 设置线条颜色,透明度随涟漪计数变化  
                    context.strokeStyle = 'hsla(0, 0%, 100%, ' + (this.MAX_RIPPLE_COUNT - this.rippleCount) / this.MAX_RIPPLE_COUNT + ')';  
                    // 坐标转换  
                    context.translate(axis.x + this.offsetY * axis.rate * (this.theta <= Math.PI ? -1 : 1), axis.y);  
                    context.scale(1, 0.3); // 缩放  
                    context.beginPath(); // 开始绘制路径  
                    // 绘制圆形路径  
                    context.arc(0, 0, this.rippleCount / this.MAX_RIPPLE_COUNT * this.RIPPLE_RADIUS * axis.rate, 0, Math.PI * 2, false);  
                    context.stroke(); // 描边路径  
                    context.restore(); // 恢复之前保存的路径状态和变换  
                    this.rippleCount++; // 涟漪计数增加  
                }  

                // 如果y坐标小于阈值或未设置结束角度和结束偏移,则绘制另一种效果  
                if (axis.y < this.thresholdY || (!this.endTheta || !this.endPhi)) {
    
      
                    // 如果y坐标小于等于0,则逐渐增加透明度  
                    if (this.y <= 0) {
    
      
                        this.opacity = Math.min(this.opacity + 0.01, 1);  
                    }  
                    context.save(); // 保存当前环境的状态  
                    context.globalAlpha = this.opacity; // 设置全局透明度  
                    context.fillStyle = this.shadowColor; // 设置填充颜色  
                    // 设置描边颜色  
                    context.strokeStyle = 'hsl(330, 30%,' + 40 * (0.3 + axis.rate) + '%)';  
                    // 坐标转换  
                    context.translate(axis.x, Math.max(axis.y, this.thresholdY + this.thresholdY - axis.y));  
                    context.rotate(Math.PI - this.theta); // 旋转  
                    context.scale(axis.rate * -Math.sin(this.phi), axis.rate); // 缩放  
                    context.translate(0, this.offsetY); // 坐标偏移  
                    this.renderCherry(context, axis); // 调用另一个绘制函数  
                    context.restore(); // 恢复之前保存的路径状态和变换  
                }  

                // 绘制主体部分  
                context.save(); // 保存当前环境的状态  
                context.fillStyle = this.entityColor; // 设置填充颜色  
                // 设置描边颜色  
                context.strokeStyle = 'hsl(330, 40%,' + 70 * (0.3 + axis.rate) + '%)';  
                // 坐标转换  
                context.translate(axis.x, axis.y + Math.abs(this.SINK_OFFSET * Math.sin(this.psi) * axis.rate));  
                context.rotate(this.theta); // 旋转  
                context.scale(axis.rate * Math.sin(this.phi), axis.rate); // 缩放  
                context.translate(0, this.offsetY); // 坐标偏移  
                this.renderCherry(context, axis); // 调用另一个绘制函数  
                context.restore(); // 恢复之前保存的路径状态和变换  

                // 如果y坐标小于视口高度的四分之一,则设置结束角度和结束偏移  
                if (this.y <= -this.renderer.height / 4) {
    
      
                    // 设置结束角度  
                    if (!this.endTheta) {
    
      
                        for (var theta = Math.PI / 2, end = Math.PI * 3 / 2; theta <= end; theta += Math.PI) {
    
      
                            if (this.theta < theta && this.theta + Math.PI / 200 > theta) {
    
      
                                this.theta = theta;  
                                this.endTheta = true;  
                                break;  
                            }  
                        }  
                    }  
                    // 设置结束偏移  
                    if (!this.endPhi) {
    
      
                        for (var phi = Math.PI / 8, end = Math.PI * 7 / 8; phi <= end; phi += Math.PI * 3 / 4) {
    
      
                            if (this.phi < phi && this.phi + Math.PI / 200 > phi) {
    
      
                                this.phi = Math.PI / 8;  
                                this.endPhi = true;  
                                break;  
                            }  
                        }  
                    }  
                }  

                // 如果未设置结束角度,则根据条件更新角度  
                if (!this.endTheta) {
    
      
                    if (axis.y == this.thresholdY) {
    
      
                        this.theta += Math.PI / 200 * ((this.theta < Math.PI / 2 || (this.theta >= Math.PI && this.theta < Math.PI * 3 / 2)) ? 1 : -1);  
                    } else {
    
      
                        this.theta += Math.PI / 500;  
                    }  
                    this.theta %= Math.PI * 2; // 确保角度在0到2π之间  
                }  

                // 如果设置了结束偏移,则更新偏移角度  
                if (this.endPhi) {
    
      
                    if (this.rippleCount == this.MAX_RIPPLE_COUNT) {
    
      
                        this.psi += this.dpsi;  
                        this.psi %= Math.PI * 2; // 确保角度在0到2π之间  
                    }  
                } else {
    
      
                    this.phi += Math.PI / ((axis.y == this.thresholdY) ? 200 : 500);  
                    this.phi %= Math.PI; // 确保角度在0到π之间  
                }  

                // 根据条件更新x和y坐标  
                if (this.y <= -this.renderer.height * this.SURFACE_RATE) {
    
      
                    this.x += 2;  
                    this.y = -this.renderer.height * this.SURFACE_RATE;  
                } else {
    
      
                    this.x += this.vx;  
                    this.y += this.vy;  
                }  

                // 返回是否在可视范围内  
                return this.z > -this.FOCUS_POSITION && this.z < this.FAR_LIMIT && this.x < this.renderer.width * 1.5;  
            }  
        };  

        // 页面加载完成后初始化渲染器  
        $(function () {
    
      
            RENDERER.init();  
        });  
    </script>  

    <!-- 音乐播放器界面 -->  
    <div class="music-player">  
        <div class="music-info">  
            <img src="images/空白logo.jpg" alt="Cover" id="cover">  
            <h2 id="title">歌曲标题</h2>  
        </div>  
        <div class="controls">  
            <button id="prev">上一首</button>  
            <button id="play">播放</button>  
            <button id="next">下一首</button>  
        </div>  
        <audio id="audioPlayer" src="images/二.mp3"></audio>  
    </div>  
    <script src="JS/音乐播放.js"></script> <!-- 引入音乐播放逻辑 -->  
</body>  

</html>

二:音乐播放.css

/* 设置body的样式 */  
body {
   
     
  display: flex; /* 使用Flexbox布局 */  
  grid: 2rem auto/repeat(2, 50%); /* CSS Grid布局,设置行大小为2rem和自适应,列重复两次,每次50% */  
  grid-column-gap: 2rem; /* 设置网格列之间的间距为2rem */  
  justify-content: center; /* Flexbox属性,子元素在主轴方向上居中对齐 */  
  width: 100%; /* 宽度为100% */  
  height: 100%; /* 高度为100% */  
  margin: 0; /* 外边距为0 */  
  padding: 0; /* 内边距为0 */  
  overflow: hidden; /* 超出部分隐藏 */  
}  

/* 设置音乐播放器的样式 */  
.music-player {
   
     
    text-align: center; /* 文本居中 */  
    padding: 30px; /* 内边距为30px */  
    border-radius: 10px; /* 边框圆角为10px */  
}  

/* 设置音乐信息中图片的样式 */  
.music-info img {
   
     
    width: 240px; /* 宽度为240px */  
    height: 200px; /* 高度为200px */  
    border-radius: 50%; /* 边框圆角为50%,即圆形 */  
    margin-bottom: 10px; /* 下外边距为10px */  
    position: relative; /* 定位方式为相对定位 */  
}  

/* 设置控制按钮的样式 */  
.controls button {
   
     
    padding: 10px 20px; /* 内边距为10px 20px */  
    margin: 5px; /* 外边距为5px */  
    cursor: pointer; /* 鼠标悬停时显示指针 */  
    font-size: 16px; /* 字体大小为16px */  
    position: relative; /* 定位方式为相对定位 */  
    background-image: linear-gradient(to right, rgba(154, 89, 168, 0.67), rgba(30, 145, 199, 0.67), rgba(0, 255, 153, 0.67)); /* 背景渐变 */  
}  

/* 设置html和body的样式 */  
html,  
body {
   
     
    width: 100%; /* 宽度为100% */  
    height: 100%; /* 高度为100% */  
    margin: 0; /* 外边距为0 */  
    padding: 0; /* 内边距为0 */  
    overflow: hidden; /* 超出部分隐藏 */  
}  

/* 设置容器的样式 */  
.container {
   
     
    width: 100%; /* 宽度为100% */  
    height: 100%; /* 高度为100% */  
    margin: 0; /* 外边距为0 */  
    position: absolute; /* 定位方式为绝对定位 */  
    padding: 0; /* 内边距为0 */  
    background-image: linear-gradient(to right, rgba(154, 89, 168, 0.67), rgba(30, 145, 199, 0.67), rgba(0, 255, 153, 0.67)); /* 背景渐变 */  
}

三:音乐播放.js

// 获取页面中的audio元素,用于播放音乐  
const player = document.getElementById('audioPlayer');  

// 获取页面中的播放按钮  
const playButton = document.getElementById('play');  

// 获取页面中的上一首按钮  
const prevButton = document.getElementById('prev');  

// 获取页面中的下一首按钮  
const nextButton = document.getElementById('next');  

// 获取页面中的歌曲标题元素,用于显示当前播放的歌曲标题  
const title = document.getElementById('title');  

// 获取页面中的歌曲封面元素,用于显示当前播放的歌曲封面  
const cover = document.getElementById('cover');  

// 定义歌曲列表  
const songs = [  
    {
   
    title: '24/7, 365', src: 'images/二.mp3', cover: 'images/24.jpg' },  
    {
   
    title: '因为喜欢你', src: 'images/因为喜欢你.mp3', cover: 'images/因为喜欢你.jpg' },  
    {
   
    title: 'Love Story', src: 'images/Love Story.mp3', cover: 'images/Lover Story.jpg' },  
    {
   
    title: 'Lover', src: 'images/Lover.mp3', cover: 'images/Lover.jpg' }  
];  

// 定义当前播放歌曲的索引  
let currentIndex = 0;  

// 加载歌曲的函数,用于更新页面上的歌曲信息和播放器源  
function loadSong(song) {
   
     
    title.textContent = song.title; // 更新歌曲标题  
    cover.src = song.cover; // 更新歌曲封面  
    player.src = song.src; // 更新播放器源  
}  

// 播放歌曲的函数  
function playSong() {
   
     
    player.play(); // 播放音乐  
    playButton.textContent = '暂停'; // 更新播放按钮的文本为“暂停”  
}  

// 暂停歌曲的函数  
function pauseSong() {
   
     
    player.pause(); // 暂停音乐  
    playButton.textContent = '播放'; // 更新播放按钮的文本为“播放”  
}  

// 为播放按钮添加点击事件监听器  
playButton.addEventListener('click', () => {
   
     
    const isPlaying = player.paused; // 判断音乐是否在播放  
    if (isPlaying) {
   
     
        playSong(); // 如果在暂停状态,则播放音乐  
    } else {
   
     
        pauseSong(); // 如果在播放状态,则暂停音乐  
    }  
});  

// 为上一首按钮添加点击事件监听器  
prevButton.addEventListener('click', () => {
   
     
    currentIndex = (currentIndex - 1 + songs.length) % songs.length; // 计算上一首歌曲的索引  
    loadSong(songs[currentIndex]); // 加载上一首歌曲  
    playSong(); // 播放上一首歌曲  
});  

// 为下一首按钮添加点击事件监听器  
nextButton.addEventListener('click', () => {
   
     
    currentIndex = (currentIndex + 1) % songs.length; // 计算下一首歌曲的索引  
    loadSong(songs[currentIndex]); // 加载下一首歌曲  
    playSong(); // 播放下一首歌曲  
});  

// 加载并播放初始歌曲  
loadSong(songs[currentIndex]);

本页面就到这里啦~ ~ ~源码复制粘贴直接可用,每一行都有详细的注释,大家可以根据自己的喜欢进行二创,大家期待一下下一个页面功能叭!!!

目录
相关文章
|
1天前
|
人工智能 前端开发
2024 川渝 Web 前端开发技术交流会「互联」:等你来报名!
2024 川渝 Web 前端开发技术交流会「互联」:等你来报名!
2024 川渝 Web 前端开发技术交流会「互联」:等你来报名!
|
3天前
|
自然语言处理 前端开发 JavaScript
推荐 10 个前端开发会用到的工具网站
本文介绍了多个前端开发工具,包括 Web Design Museum、Landing Page、Google Fonts、Lorem Ipsum、Animista、Blobmaker、Spline、CodeToGo、UnusedCSS 和 Responsively,帮助开发者提高效率和项目质量。这些工具涵盖了设计、动画、代码片段管理、响应式测试等多个方面。
17 0
推荐 10 个前端开发会用到的工具网站
|
4天前
|
存储 前端开发 JavaScript
从 Web 2.0 到 Web 3.0:前端开发的历史与未来
【10月更文挑战第4天】本文探讨了从 Web 2.0 到 Web 3.0 的前端开发演变过程。Web 2.0 时代,前端开发者从静态网页设计走向复杂交互,技术框架如 jQuery、React 和 Vue 带来了巨大的变革。而 Web 3.0 以区块链技术为核心,带来了去中心化的互联网体验,前端开发者面临与区块链交互、去中心化身份验证、分布式存储等新挑战。文章总结了 Web 2.0 和 Web 3.0 的核心区别,并为开发者提供了如何应对新技术的建议,帮助他们在新时代中掌握技能、设计更安全的用户体验。
21 0
从 Web 2.0 到 Web 3.0:前端开发的历史与未来
|
5天前
|
前端开发 JavaScript 开发者
web前端需要学什么
web前端需要学什么
|
7天前
|
前端开发 JavaScript 开发者
Web组件:一种新的前端开发范式
【10月更文挑战第9天】Web组件:一种新的前端开发范式
11 2
|
7天前
|
前端开发 JavaScript 开发者
探索现代Web前端技术:React框架入门
【10月更文挑战第9天】 探索现代Web前端技术:React框架入门
|
10天前
|
前端开发 JavaScript 数据可视化
前端实用网站
【10月更文挑战第3天】
10 1
|
4天前
|
移动开发 前端开发 JavaScript
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
29 0
|
4天前
|
存储 安全 前端开发
在前端开发中需要考虑的常见web安全问题和攻击原理以及防范措施
在前端开发中需要考虑的常见web安全问题和攻击原理以及防范措施
25 0
|
4天前
|
存储 前端开发 API
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
31 0