音乐播放器
开篇(请大家看完):此网站写给挚爱,后续页面还会慢慢更新,大家敬请期待~ ~ ~
此前端框架,主要侧重于前端页面的视觉效果和交互体验。通过运用各种前端技术和创意,精心打造了一系列引人入胜的页面特效,会为大家带来全新的浏览体验。
同时,我非常支持和鼓励大家对这个框架进行二次创作或修改。您可以根据自己的需求和喜好,对框架进行个性化的定制和扩展,以打造出更符合自己品味的页面效果。
但请注意,如果您打算将这个框架转发给其他人或用于其他场合,请务必注明原创来源。让我们一起维护一个良好的创作环境。
最后,轻舟会继续更新和完善这个前端页面特效框架,为大家带来更多有趣、实用的功能和效果。感谢您的支持和关注!
页面效果:整体色调背景采用柔和渐变的方式呈现,与主页面的“毒药水式”色彩搭配形成了强烈的对比;周边花瓣缓缓飘落到水面之上形成涟漪。整体给人一种温馨、浪漫的感觉,还可以通过中间的3个按钮来控制音乐的切换和播放
一:音乐播放.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]);
本页面就到这里啦~ ~ ~源码复制粘贴直接可用,每一行都有详细的注释,大家可以根据自己的喜欢进行二创,大家期待一下下一个页面功能叭!!!