三、PHP 演示源码(推荐方式,含完整前后端)
包里已附带可直接部署的 demo.php:上传到你网站根目录,浏览器访问 https://你的域名/demo.php 即可看到悬浮窗效果。后端用 PHP 请求接口(服务端做代理),前端只负责渲染与播放。完整源码如下:
<?php
// demo.php - 网易云音乐悬浮窗播放器演示(PHP 服务端代理版)
// 部署:放到你网站根目录,访问 https://你的域名/demo.php
define('API', 'https://wymusic.id.haifengyun.cn/api.php'); // API 基地址
// 通用请求函数:PHP 服务端代为请求接口,避免前端直连跨域
function api_request($params) {
$url = API . '?' . http_build_query($params);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (demo)');
$res = curl_exec($ch);
curl_close($ch);
return json_decode($res, true);
}
$do = isset($_GET['do']) ? $_GET['do'] : '';
// 接口代理:search / playlist / url 全部转发给官方 API
if (in_array($do, ['search', 'playlist', 'url'], true)) {
header('Content-Type: application/json; charset=utf-8');
if ($do === 'search') {
$kw = trim($_GET['keyword'] ?? '');
if ($kw === '') { echo json_encode(['code' => 0, 'msg' => '关键词为空']); exit; }
$params = ['action' => 'search', 'keyword' => $kw, 'type' => intval($_GET['type'] ?? 1)];
} elseif ($do === 'playlist') {
$params = ['action' => 'playlist', 'id' => intval($_GET['id'] ?? 0)];
} else {
$params = ['action' => 'url', 'id' => intval($_GET['id'] ?? 0)];
}
$d = api_request($params);
echo json_encode($d ?: ['code' => 0, 'msg' => '请求失败']);
exit;
}
// 后台歌单模式:想换歌只改这个 PID,前端代码不用动
$PID = 3778678; // ← 换成你在查询工具里复制的歌单 ID
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>音乐悬浮窗演示</title>
</head>
<body style="font-family:-apple-system,sans-serif;margin:0">
<!-- 悬浮窗(右下角固定) -->
<div id="mp" style="position:fixed;right:12px;bottom:12px;width:300px;height:420px;background:#fff;border-radius:14px;box-shadow:0 6px 24px rgba(0,0,0,.18);z-index:9999;display:flex;flex-direction:column;overflow:hidden">
<div style="padding:12px 14px;background:linear-gradient(135deg,#EC4141,#F08A5D);color:#fff;font-size:14px;font-weight:700">🎵 音乐播放器</div>
<div style="display:flex;gap:8px;padding:10px 12px">
<input id="mp_kw" style="flex:1;height:36px;border:1px solid #EBEDF0;border-radius:18px;padding:0 14px;font-size:13px;outline:none" placeholder="输入歌名 / 歌手搜索点歌">
<button id="mp_btn" style="height:36px;border:none;border-radius:18px;padding:0 16px;background:#EC4141;color:#fff;font-size:13px;cursor:pointer">搜索</button>
</div>
<div id="mp_list" style="flex:1;overflow-y:auto;padding:4px 6px 8px"></div>
<div id="mp_bar" style="display:none;padding:10px 12px;border-top:1px solid #EBEDF0;font-size:13px;align-items:center;gap:10px"></div>
</div>
<script>
// 前端只请求自己的 demo.php,由 PHP 服务端代理去官方 API(无跨域问题)
var AUDIO = new Audio();
function render(list) {
var box = document.getElementById('mp_list');
box.innerHTML = '';
(list || []).forEach(function (s) {
var d = document.createElement('div');
d.style.cssText = 'display:flex;align-items:center;gap:10px;padding:8px 10px;cursor:pointer;border-radius:8px';
d.innerHTML = '<img src="' + s.pic + '" style="width:38px;height:38px;border-radius:8px;object-fit:cover">' +
'<div style="flex:1;min-width:0"><div style="font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + s.name + '</div>' +
'<div style="font-size:11px;color:#646A73;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + (s.artist || '') + '</div></div>';
d.onclick = function () { play(s); };
box.appendChild(d);
});
}
function play(s) {
fetch('demo.php?do=url&id=' + s.id).then(function (r) { return r.json(); }).then(function (d) {
if (d.code !== 1 || !d.url) return;
AUDIO.src = d.url; AUDIO.play();
var bar = document.getElementById('mp_bar');
bar.style.display = 'flex';
bar.innerHTML = '<span style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + s.name + '</span>' +
'<span style="color:#EC4141;font-weight:700;cursor:pointer" onclick="AUDIO.paused?AUDIO.play():AUDIO.pause()">播放/暂停</span>';
});
}
// 用户搜索点歌(模式一)
document.getElementById('mp_btn').onclick = function () {
var kw = document.getElementById('mp_kw').value.trim();
if (!kw) return;
fetch('demo.php?do=search&keyword=' + encodeURIComponent(kw) + '&type=1')
.then(function (r) { return r.json(); })
.then(function (d) { if (d.code === 1) render(d.list); });
};
document.getElementById('mp_kw').addEventListener('keyup', function (e) {
if (e.key === 'Enter') document.getElementById('mp_btn').onclick();
});
// 后台歌单模式(模式二):加载 PHP 里设好的 $PID,用户无感知
fetch('demo.php?do=playlist&id=' + )
.then(function (r) { return r.json(); })
.then(function (d) { if (d.code === 1) render(d.list); });
</script>
</body></html>
关键点:PHP 只做转发,前端永远请求你自己的域名(无跨域限制);后台换歌只需改 $PID 一个变量;用户界面不展示歌曲 ID。