前言
最近在Github上看到了一個音樂可視化前端庫:vudio.js https://github.com/alex2wong/vudio.js
效果有點炫酷:
本人是非常喜歡將音頻可視化的效果听系,聯想到之前的網易云地址解析API钉疫,決定將兩者結合绘闷,做個簡單的網易云音樂可視化小工具节值。
今天將制作過程記錄一下璧瞬。
除此之外嗅绸,我也將它推送到了Gitee Page上,你可以通過以下地址體驗(受限于網易云地址解析API断国,無法播放VIP音樂贤姆,有點遺憾):
https://txb582.gitee.io/%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90%E5%8F%AF%E8%A7%86%E5%8C%96/index.html
思路
大體思路是:
1、可視化工具獲取用戶輸入的網易云分享鏈接稳衬。
2霞捡、調用解析API將分享地址解析為音樂真實地址實現播放。
3薄疚、調用vudio.js將音樂可視化碧信。
解析API和可視化庫都準備好了,主要的開發(fā)工作就只有可視化工具頁面的開發(fā)
在該工具中街夭,用到了以下東西:
- axios網絡請求庫
- 網易云地址解析API
- 音頻可視化庫vudio.js
開發(fā)
1砰碴、建立常用的目錄結構
2、頁面結構
頁面主要分為兩大塊
1板丽、可視化動畫區(qū)域
2呈枉、懸浮于右側的可收拉菜單
頁面布局代碼
<body id="body">
<div id="box-show">
</div>
<div id="box-menu">
</div>
</body>
然后在可視化區(qū)域添加
<audio>和<canvas>元素,用于音樂的播放和可視化動畫的繪制檐什。
<body id="body">
<div id="box-show">
<audio id="audio" src=""></audio>
<canvas id="canvas">
你的瀏覽器不支持Canvas
</canvas>
</div>
<div id="box-menu">
</div>
</body>
在菜單中添加
兩個<div>用于放置收放按鈕和菜單主體
<body id="body">
<div id="box-show">
<audio id="audio" src=""></audio>
<canvas id="canvas">
你的瀏覽器不支持Canvas
</canvas>
</div>
<div id="box-menu">
<div id="box-menu-pull">
</div>
<div id="box-menu-list">
</div>
</div>
</body>
在按鈕區(qū)域放置一個<button>作為菜單收放按鈕
在菜單主體區(qū)域放置
<img>用于顯示關照二維碼
<span>用于顯示提示
兩個用div包裹起來的<input>實現搜索欄
還有兩個嵌套的<div>用于顯示播放的歷史記錄碴卧,用兩個<div>嵌套是因為后續(xù)為了不讓滾動條影響頁面美觀,使用嵌套的方式通過位移來隱藏滾動條乃正。
<body id="body">
<div id="box-show">
<audio id="audio" src=""></audio>
<canvas id="canvas">
你的瀏覽器不支持Canvas
</canvas>
</div>
<div id="box-menu">
<div id="box-menu-pull">
<button>></button>
</div>
<div id="box-menu-list">
<img src="./images/微信公眾號二維碼.jpg">
<span> 掃碼關注我們 | MF工作室 </span>
<div>
<input id="search-input" type="text" placeholder="網易云音樂鏈接">
<input id="search-button" type="button" value="GO">
</div>
<div>
<div id="box-menu-list-historical"></div>
</div>
</div>
</div>
</body>
然后引入必要的文件
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>網易云音樂可視化工具 | MF工作室</title>
<link rel="shortcut icon" href="./images/logo.ico" type="image/x-icon">
<meta http-equiv="Access-Control-Allow-Origin" content="viapi.cn/wyy">
<link rel="stylesheet" href="./css/index.css">
<script src="./js/vudio.js"></script>
<script src="./js/axios.min.js"></script>
<script src="./js/index.js"></script>
</head>
3、頁面樣式
/* 清空所有邊距并禁止用戶復制選擇頁面內容 */
* {
margin: 0px;
border: 0px;
padding: 0px;
user-select: none;
box-sizing: border-box;
}
/* 將html,body 設置與窗口一致, 方便高度使用百分比 */
html, body {
width: 100%;
height: 100%;
}
/* 設置頁面背景漸變, 如果你想, 也可以用圖片替代 */
body {
background-image: linear-gradient(#f28fb2, #6cbffd);
background-repeat: no-repeat;
background-size: cover;
}
/* 可視化區(qū)域設置為充滿body元素 */
#box-show {
width: 100%;
height: 100%;
display: flex;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#box-show>canvas {
max-width: 100%;
}
#box-show>audio {
display: none;
}
/* 將菜單設置為絕對定位, 固定在頁面右側 */
#box-menu {
width: 350px;
height: 100%;
position: fixed;
top: 0px;
right: 0px;
opacity: 0.6;
transition: right 0.5s;
display: flex;
}
/* 收拉按鈕區(qū)域使用flex布局, 建按鈕居中顯示 */
#box-menu-pull {
width: 50px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
/* 設置收拉按鈕樣式 */
#box-menu-pull>button {
width: 50px;
height: 50px;
font-size: 30px;
border-radius: 50% 0% 0% 50%;
outline: none;
background-color: rgba(142, 194, 243, 0.8);
color: #FFFFFF;
}
/* 使用flex布局, 將菜單主體中的內容垂直居中顯示 */
#box-menu-list {
width: 300px;
height: 100%;
padding-top: 20px;
padding-bottom: 20px;
margin-bottom: 20px;
background-color: rgba(142, 194, 243, 0.8);
display: flex;
flex-direction: column;
align-items: center;
overflow-y: auto;
}
/* 公眾號二維碼樣式 */
#box-menu-list>img {
width: 85%;
border: 5px solid rgba(151, 199, 231, 0.8);
border-radius: 10px;
}
/* 提示語樣式 */
#box-menu-list>span:nth-of-type(1) {
color: #ffffff;
}
/* 搜索欄樣式 */
#box-menu-list>div:nth-of-type(1) {
width: 90%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
border-radius: 5px;
}
/* 搜索欄輸入框樣式 */
#search-input {
height: 100%;
width: calc(100% - 40px);
background-color: rgba(151, 199, 231, 0.8);
outline: none;
padding-left: 5px;
padding-right: 5px;
color: #FFFFFF;
}
#search-input::-webkit-input-placeholder { color: #FFFFFF; }
#search-input::-moz-placeholder { color: #FFFFFF; }
#search-input:-moz-placeholder { color: #FFFFFF; }
#search-input:-ms-input-placeholder { color: #FFFFFF; }
/* 搜索欄提交按鈕樣式 */
#search-button {
width: 40px;
height: 100%;
background-color: rgba(151, 199, 231, 0.8);
outline: none;
border-left: 1px solid #c8d5dd;
color: #FFFF;
}
/* 歷史播放記錄顯示區(qū)域樣式 */
#box-menu-list>div:nth-of-type(2) {
width: 100%;
height: 55%;
overflow: hidden;
}
#box-menu-list-historical{
width: 100%;
height: 100%;
overflow: auto;
/* 相對于正常位置右移15像素, 這樣就可以使用上層元素遮蓋掉滾動條了 */
position: relative;
right: -15px;
}
#box-menu-list-historical>button {
display: block;
padding: 10px;
width: 95%;
border-radius: 5px;
margin-top: 10px;
color: #FFFFFF;
background-color: rgba(151, 199, 231, 0.8);
position: relative;
right: 15px;
outline: none;
}
4婶博、頁面邏輯
window.onload = function () {
var menu = document.getElementById("box-menu");
var menu_pull_button = document.querySelector("#box-menu-pull > button");
var box_menu_list_historical = document.getElementById("box-menu-list-historical");
var audio_object = document.getElementById("audio");
// 允許跨域讀取音頻, 如果不設置, 在調用API時瀏覽器會因為同源策略阻止音樂拉取
audio_object.crossOrigin = "anonymous";
var canvas_object = document.getElementById("canvas");
var search_button = document.getElementById("search-button");
var search_input = document.getElementById("search-input");
// 側邊菜單點擊 拉出/隱藏
var is_pull = true;
menu_pull_button.onclick = function () {
if (is_pull) {
menu.style.right = "-300px";
menu_pull_button.innerText = "<";
is_pull = false;
} else {
menu.style.right = "0px";
menu_pull_button.innerText = ">";
is_pull = true;
}
}
// 提交按鈕點擊處理
search_button.onclick = function () {
// 從網易云分享鏈接中提取音樂ID
source_music_url = search_input.value;
source_musid_id = ((source_music_url.split("?")[1]).split("&")[0]).split("=")[1];
// 調用API解析音樂真實地址, API具體使用方法參考: https://api.565.ink/docs#/Lan%E5%B7%A5%E5%85%B7%E7%AE%B1/wangyiyunmc_163mc_get
axios.get(`https://api.565.ink/163mc?id=${source_musid_id}`).then(function (response) {
console.log(response.data);
music_url = response.data["resulturl"];
audio_object.setAttribute("src", music_url);
audio_object.play();
// 向菜單列表插入歷史播放記錄按鈕
let button = document.createElement("button");
button.setAttribute("data-music-url", response.data["resulturl"]);
button.innerText = source_musid_id;
button.onclick = function () {
audio_object.setAttribute("src", this.getAttribute("data-music-url"));
audio_object.play();
}
box_menu_list_historical.appendChild(button)
})
}
// 音頻可視化, 具體使用方法參考: https://github.com/alex2wong/vudio
var vudio = new Vudio(audio_object, canvas_object, {
effect: 'circlebar',
accuracy: 128,
width: 400,
height: 400,
waveform: {
maxHeight: 80,
minHeight: 1,
spacing: 1,
shadowBlur: 0,
fadeSide: true,
horizontalAlign: 'center',
verticalAlign: 'middle'
}
});
vudio.dance();
}