当前位置: 首页 > news >正文

微信小程序---暮之沧蓝音乐小程序

前言

本文介绍了一个基于Express搭建的静态文件服务器和小程序音乐播放器的实现方案。

主要内容包括:

1) 使用Express、serve-static等模块搭建支持文件上传和浏览的静态服务器;

2) 开发微信小程序音乐播放器,包含推荐页、播放器和播放列表三个标签页;

3) 实现音乐播放控制功能,包括播放/暂停、进度条拖动、自动切歌等;

4) 设计UI界面,包含轮播图、音乐推荐列表、播放控制面板等组件。

系统通过3000端口提供静态文件服务,小程序通过HTTP请求获取音频文件并进行播放管理。

结果展示

前提准备

1.1 搭建一个简单的静态文件服务器,并支持文件上传功能


1.2 创建index.js文件(注意:创建的文件夹一定是英文,中文cmd不能识别)

1.3 编辑index.js文件

// 搭建一个简单的静态文件服务器,并支持文件上传功能
// 静态文件服务:通过 serve-static 和 serve-index 提供 ./htdocs 目录下的文件浏览和下载。
// 文件上传:通过 multiparty 解析上传的文件,并保存到 ./htdocs/upfile 目录。
// 服务器监听:在 3000 端口启动 HTTP 服务器。
var express = require('express');
var serveIndex = require('serve-index');
var serveStatic = require('serve-static');
var multiparty = require('multiparty');
var path = require('path'); // 用于路径处理
var fs = require('fs');     // 用于检查目录var LOCAL_BIND_PORT = 3000;
var app = express();// 确保上传目录存在
const uploadDir = path.join(__dirname, 'htdocs', 'upfile');
if (!fs.existsSync(uploadDir)) {fs.mkdirSync(uploadDir, { recursive: true });
}// 文件上传接口
app.post('/upload', function (req, res) {var form = new multiparty.Form();form.encoding = 'utf-8';form.uploadDir = uploadDir;form.maxFilesSize = 4 * 1024 * 1024; // 4MBform.parse(req, function (err, fields, files) {if (err) {console.log('parse error: ' + err);} else {console.log('parse files: ' + JSON.stringify(files));}res.writeHead(200, { 'content-type': 'text/plain;charset=utf-8' });res.write('received upload');res.end();});
});// 静态文件服务
var serve = serveStatic('./htdocs');
app.use('/', serveIndex('./htdocs', { 'icons': true }));
app.use('/', serve); // ✅ 使用中间件自动处理所有静态请求// 启动服务器
console.log(`✅ 静态文件服务器已启动:http://localhost:${LOCAL_BIND_PORT}`);
console.log(`📁 访问目录:./htdocs`);
console.log(`📥 上传目录:./htdocs/upfile`);
console.log(`🔧 按 Ctrl + C 停止服务器`);
app.listen(LOCAL_BIND_PORT);

1.4 在此目录(music_bg)路径输入cmd,运行以下命令

npm init -y                 # 自动创建package,json配置文件npm install express --save  # 安装Express框架,用于快速搭建HTTP服务器npm install nodemon -g      # 安装nodemon监控文件修改

1.5 运行index.js文件

node index.js

1.6 打开浏览器,运行http://127.0.0.1:3000

可以找些音频文件放进upfile文件夹

后期需要将如“http://127.0.0.1:3000/upfile/%5B%E5%85%8D%E8%B4%B9%E4%BC%B4%E5%A5%8F%5DAmbient.mp3

填入代码里

代码展示

整体结构

2.1 index.json

{"navigationBarBackgroundColor": "#fff","navigationBarTitleText": "暮之沧蓝音乐","navigationBarTextStyle":"black"
}

2.2 index.wxml

<!-- 轮播图 -->
<view class="tab"><!-- bindtap="changeItem",单击tab区域切换到对应的标签页 --><view class="tab-item {{ tab==0?'active:':''}}" bindtap="changeItem" data-item="0">音乐推荐</view><view class="tab-item {{ tab==1?'active:':''}}" bindtap="changeItem" data-item="1">播放器</view><view class="tab-item {{ tab==2?'active:':''}}" bindtap="changeItem" data-item="2">播放列表</view>
</view>
<!-- 主体内容 -->
<view class="content"><swiper current="{{ item }}" bindchange="changeTab"><swiper-item><include src="info.wxml" /></swiper-item><swiper-item><include src="play.wxml" /></swiper-item><swiper-item><include src="playlist.wxml" /></swiper-item></swiper>
</view>
<!-- 底部播放器 -->
<view class="player"><image class="player-cover" src="{{ play.coverImgUrl}}" /><view class="player-info"><view class="player-info-title">{{ play.title }}</view><view class="player-info-singer">{{ play.singer }}</view></view><view class="player-controls"><!-- 切换到播放列表 --><image src="/images/B.png" bindtap="changePage" data-page="2"/><!-- 播放 --><image wx:if="{{ state=='paused'}}" src="/images/ZT.png" bindtap="play"/><image wx:else src="/images/BF.png" bindtap="pause"/><!-- 下一曲 --><image src="/images/XYQ.png" bindtap="next"/></view>
</view>

2.3 index.wxss

page {display: flex;flex-direction: column;background: rgb(207, 236, 247);color: rgb(70, 68, 68);height: 100%;
}.tab {display: flex;
}.tab-item {flex: 1;font-size: 10pt;text-align: center;line-height: 72rpx;border-bottom: 6rpx solid white;
}.content {flex: 1;
}.content > swiper {height: 100%;
}.player {background:rgb(213, 238, 247);border-top: 1rpx solid black;height: 112rpx;
}.tab-item.active {color: red;border-block-color: red;
}.content-info {height: 100%;
}
/* 隐藏滚动条 */
::-webkit-scrollbar {width: 0;height: 0;color: transparent;
}.content-info-slide {height: 310rpx;margin-bottom: 20rpx;
}.content-info-slide image{width: 100%;height: 100%;
}.content-info-portal {display: flex;margin-bottom: 15rpx;
}.content-info-portal > view {flex: 1;font-size: 10pt;text-align: center;
}.content-info-portal image {width: 90rpx;height: 90rpx;display: block;margin: 20rpx auto;
}.content-info-list {font-size: 10pt;margin-bottom: 20rpx;
}.content-info-list > .list-title {font-size: 15pt;margin: 50rpx 35rpx;color: brown;
}.content-info-list > .list-inner {display: flex;flex-wrap: wrap;margin: 0 20rpx;
}.content-info-list > .list-inner > .list-item {flex: 1;
}.content-info-list > .list-inner > .list-item > image {display: block;width: 200rpx;height: 200rpx;margin: 0 auto;border-radius: 10rpx;border: 1rpx solid #555;
}.content-info-list > .list-inner > .list-item > view {width: 200rpx;margin: 10rpx auto;font-size: 10pt;
}/* 播放器样式 */
.player {display: flex;align-items: center;background: rgb(207, 236, 247);border-top: 1rpx solid black;height: 115rpx;
}.player-cover {width: 80rpx;height: 80rpx;margin-left: 15rpx;border-radius: 8rpx;border: 1rpx solid black;
}.player-info {flex: 1;font-size: 10pt;line-height: 50rpx;margin-left: 20rpx;padding-bottom: 10rpx;
}.player-info-singer {color: gray;
}.player-controls image {width: 50rpx;height: 50rpx;margin-right: 30rpx;
}/* 播放器 */
.content-play {display: flex;justify-content: space-around;flex-direction: column;height: 100%;text-align: center;
}.content-play-info > view {color: gray;font-size: 12pt;
}.content-play-cover image {animation: rotateImage 10s linear infinite;width: 400rpx;height: 400rpx;border-radius: 50%;border: 1rpx solid gray;
}@keyframes rotateImage {from {transform: rotate(0deg);}to {transform: rotate(360deg);}
}.content-play-progress {display: flex;align-items: center;margin: 0 35rpx;font-size: 9pt;text-align: center;
}.content-play-progress > view {flex: 1;
}/* 播放列表 */
.playlist-item {display: flex;align-items: center;border-bottom: 1rpx solid black;height: 115rpx;
}.playlist-cover {width: 80rpx;height: 80rpx;margin-left: 15rpx;border-radius: 8rpx;border: 1rpx solid black;
}.playlist-info {flex: 1;font-size: 10pt;line-height: 40rpx;margin-left: 20rpx;padding-bottom: 5rpx;
}.playlist-info-singer {color: gray;
}.playlist-controls {font-size: 10pt;margin-right: 20rpx;color: red;
}

2.4 info.wxml

<scroll-view class="content-info" scroll-y><!-- 轮播图 --><view style="background: white; height: 1300rpx;"><swiper class="content-info-slide" indicator-color="rgba(255,255,255,.5)" indicator-active-color="#fff" indicator-dots circular autoplay><swiper-item><image src="/images/banner.png"/></swiper-item><swiper-item><image src="/images/banner2.png"/></swiper-item><swiper-item><image src="/images/banner3.png"/></swiper-item></swiper>	<!-- 功能按钮 --><view class="content-info-portal"><view><image src="/images/F1.png"/><text>私人漫游</text></view><view><image src="/images/F2.png"/><text>每日推荐</text></view><view><image src="/images/F3.png"/><text>新歌榜单</text></view></view><!-- 为你推荐 --><view class="content-info-list"><view class="list-title">为你推荐</view><view class="list-inner"><view class="list-item"><image src="/images/T1.png"/><view>City Of Stars</view></view><view class="list-item"><image src="/images/T2.png"/><view>那时雨</view></view><view class="list-item"><image src="/images/T3.png"/><view>Show Me Love</view></view><view class="list-item"><image src="/images/T4.png"/><view>AM</view></view><view class="list-item"><image src="/images/T5.png"/><view>习惯失恋</view></view><view class="list-item"><image src="/images/T6.png"/><view>幻想是痛的延续</view></view></view></view></view><!-- <view>已到达最底部</view> -->
</scroll-view>

2.5 play.wxml

<!-- 播放器页面 -->
<view class="content-play"><!-- 显示音乐信息 --><view class="content-play-info"><text>{{ play.title }}</text><view>--{{ play.singer }}--</view></view><!-- 显示专辑封面 --><view class="content-play-cover"><image src="{{ play.coverImgUrl }}" style="animation-play-state: {{ state }} " /></view><!-- 显示播放进度和时间 --><view class="content-play-progress"><text>{{ play.currentTime }}</text><view><slider bindchange="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{ play.percent }}" /></view>	<text>{{ play.duration }}</text></view>
</view>

2.6 playlist.wxml

<!-- 播放列表 -->
<scroll-view class="content-playlist" scroll-y><view class="playlist-item" wx:for="{{ playlist }}" wx:key="id" bindtap="change" data-index="{{ index }}"><image class="playlist-cover" src="{{ item.converImgUrl }}"/><view class="playlist-info"><view class="playlist-info-title">{{ item.title }}</view><view class="playlist-info-singer">{{ item.singer }}</view></view><view class="playlist-controls"><text wx:if="{{ index==playIndex }}">正在播放</text></view></view></scroll-view>

2.7 index.js

// index.jsPage({data: {// 切换标签页的值item: 0,// 标签页索引tab: 0,// 播放列表数据playlist: [{id: 1,title: "City Of Stars",singer: "王OK",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T1.png"},{id: 2,title: "那时雨",singer: "徐良",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T2.png"},{id: 3,title: "Show Me Love",singer: "WizTheMC",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T3.png"},{id: 4,title: "AM",singer: "T-Chenxi",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T4.png"},{id: 5,title: "习惯失恋",singer: "容祖儿",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T5.png"},{id: 6,title: "幻想是痛的延续",singer: "匿名",src: "{此处填入前面服务器生成的网址}",converImgUrl: "/images/T6.png"},],// 播放状态,running表示正在播放state: "paused",// 当前播放的曲目在播放列表数组中的索引值playIndex: 0,play: {// 播放时长currentTime: "00:00",duration: "00:00",// 播放进度percent: 0,title: "",singer: "",converImgUrl: "/images/T1.png"},},// 切换到对应的标签页changeItem: function(e) {this.setData({item: e.target.dataset.item})},// 更改当前标签页的索引changeTab: function(e){this.setData({tab:e.detail.current})},// 实现音乐播放功能audioCtx: null,onReady: function(){// 控制播放器页面的进度条的进度与时间显示this.audioCtx = wx.createInnerAudioContext()var that = this// 播放失败检测this.audioCtx.onError(function(){console.log("播放失败:" + that.audioCtx.src)})// 播放完成自动切换下一曲this.audioCtx.onEnded(function(){that.next()})// 自动更新播放进度this.audioCtx.onPlay(function(){})// 获取音乐状态信息this.audioCtx.onTimeUpdate(function(){that.setData({"play.duration": formatTime(that.audioCtx.duration),"play.currentTime": formatTime(that.audioCtx.currentTime),"play.percent": that.audioCtx.currentTime / that.audioCtx.duration * 100})})// 默认选择第一首歌this.setMusic(0)// 格式化时间function formatTime(time) {var minute = Math.floor(time / 60) % 60;var second = Math.floor(time) % 60;return (minute < 10 ? '0' + minute: minute) + ':' + (second < 10 ? '0' + second: second)}},// 获取当前滚动条的进度sliderChange: function(e) {var second = e.detail.value * this.audioCtx.duration / 100this.audioCtx.seek(second)},// 切换当前播放的歌曲setMusic: function(index){var music = this.data.playlist[index]this.audioCtx.src = music.srcthis.setData({playIndex: index,"play.title": music.title,"play.singer": music.singer,"play.coverImgUrl": music.converImgUrl,"play.currentTime": "00:00","play.duration": "00:00","play.percent": 0})},// 处理播放与暂停play: function() {this.audioCtx.play()this.setData({state: "running"})},pause: function() {this.audioCtx.pause()this.setData({state: "paused"})},// 下一曲按钮next: function() {var index = this.data.playIndex >= this.data.playlist.length - 1 ? 0 : this.data.playIndex + 1this.setMusic(index)// 状态为暂停,不要立即播放if (this.data.state === 'running') {this.play()}},// 点击列表歌曲并播放change: function(e) {this.setMusic(e.currentTarget.dataset.index)this.play()}})


文章转载自:

http://wPd3jFdL.hLfnh.cn
http://F0e9t6vA.hLfnh.cn
http://B9LrTqul.hLfnh.cn
http://qAzTE1uz.hLfnh.cn
http://T1LlP12Y.hLfnh.cn
http://x8dii2wK.hLfnh.cn
http://ePgeXP5y.hLfnh.cn
http://z0I7yEJb.hLfnh.cn
http://OSItYI0h.hLfnh.cn
http://fp9uprXa.hLfnh.cn
http://m56EAGJq.hLfnh.cn
http://OQX8CDlh.hLfnh.cn
http://fVfspsGZ.hLfnh.cn
http://R6HmoLCj.hLfnh.cn
http://63oRgExg.hLfnh.cn
http://4kCxXCWT.hLfnh.cn
http://VOI3jfgN.hLfnh.cn
http://pcX1wKI3.hLfnh.cn
http://BxXEZ1HZ.hLfnh.cn
http://qmlGaF2L.hLfnh.cn
http://mGp44KXx.hLfnh.cn
http://t64D6155.hLfnh.cn
http://SCKdBrGf.hLfnh.cn
http://4gflBdou.hLfnh.cn
http://HrpdL0yB.hLfnh.cn
http://hOQ7XPFy.hLfnh.cn
http://dUUiQLjE.hLfnh.cn
http://EAL75WD1.hLfnh.cn
http://EwqvJGtV.hLfnh.cn
http://vmNrMWGG.hLfnh.cn
http://www.dtcms.com/a/387351.html

相关文章:

  • springboot jar包部署到服务器上后,logback按日期归档不正确,今天的日志归档到昨天了,日志中的时间也不正确
  • Spring Boot Logback 日志配置详解:从基础到分布式追踪
  • 辉视养老方案:重塑老年生活的温馨与安心
  • 通过商业智能(BI)可视化数据分析了解布洛芬的产销情况
  • 健康大数据专业能转行做医疗数据分析吗?
  • antiword为什么在ubuntu22.04上面不乱码,而在mac上出现乱码
  • Paperless-ngx v2.18.4在Ubuntu 24.04上的完整离线安装步骤(非Docker)
  • Ubuntu 18.04 搭建 Kubernetes 1.27.4 集群全流程(附问题排查)
  • Ubuntu 18.04 LTS 安装 6.10.10 内核
  • Windows 11 下使用 WSL2 安装 Ubuntu 22.04 步骤
  • 在 WSL 中通过 Bash 函数快速转换 Windows 路径为 Ansible/WSL 路径
  • 【ubuntu24.04】 nvidia-smi监控GPU 利用率
  • 《嵌入式硬件(十四):基于IMX6ULL的通用目的定时器(GPT)操作》
  • 鸿蒙Next Web调试与维测全攻略:从DevTools到专项测试
  • 基于运行设计域(ODD)的安全论证方法
  • 鸿蒙HarmonyOS界面开发-组件动态创建(一)
  • 网络安全风险评估中元模型构建与实例应用
  • 鸿蒙5.0应用开发——V2装饰器@ObservedV2和@Trace的使用
  • xkInfoScan 是一款集成化的网络信息收集与安全扫描工具,支持 IP / 域名 / URL /信息追踪多维度目标探测
  • 解决 Windows 系统下 TDengine 数据恢复及迁移问题
  • PocketBase 是一个‌开源的轻量级后端框架‌,基于 Go 语言开发
  • 苹果新手机和旧手机怎么传输数据?新手避坑指南
  • Maven 只打包部分模块,跳过单元测试... 常用打包参数
  • 【maven01】依赖管理的工具
  • BP神经网络多输入多输出回归预测+SHAP可解释分析+新数据预测(MATLAB完整源码)
  • MATLAB 时间序列小波周期分析
  • 计算机视觉进阶教学之DNN模块
  • 大模型无需懂MCP:工具调用范式的架构革命与实践指南
  • 剑指offer题单 9.14
  • IIS 站点 http 请求412问题解决