HTML

做一个网易云音乐可视化工具

2020-10-04  本文已影响0人  MangfuStudio

前言

最近在Github上看到了一个音乐可视化前端库:vudio.js https://github.com/alex2wong/vudio.js

效果有点炫酷:



本人是非常喜欢将音频可视化的效果,联想到之前的网易云地址解析API,决定将两者结合,做个简单的网易云音乐可视化小工具。

今天将制作过程记录一下。

以下是演示效果:
https://static.cdnjs.cloud/2020104_box/6f27a474b6a546c71ea3b6951a16e813_2020-10-04-16-55-23.mp4_2020-10-04-16-55-23.mp4

除此之外,我也将它推送到了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和可视化库都准备好了,主要的开发工作就只有可视化工具页面的开发
在该工具中,用到了以下东西:

开发

1、建立常用的目录结构

2、页面结构

页面主要分为两大块
1、可视化动画区域
2、悬浮于右侧的可收拉菜单



页面布局代码

<body id="body">
    <div id="box-show">
    </div>
    <div id="box-menu">
    </div>
</body>

然后在可视化区域添加
<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>

在按钮区域放置一个<button>作为菜单收放按钮
在菜单主体区域放置
<img>用于显示关照二维码
<span>用于显示提示
两个用div包裹起来的<input>实现搜索栏
还有两个嵌套的<div>用于显示播放的历史记录,用两个<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">
            <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;
}
/* 可视化区域设置为充满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;
}
/* 收拉按钮区域使用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;
}
/* 历史播放记录显示区域样式 */
#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();
}

上一篇下一篇

猜你喜欢

热点阅读