600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 通过网易云api实现一个简单的音乐播放器

通过网易云api实现一个简单的音乐播放器

时间:2023-05-03 09:54:57

相关推荐

通过网易云api实现一个简单的音乐播放器

这次文章我来实现一个简易的播放器,这里调用了网易云的api来获取他的音乐,可以自行下载其文件,本次案例需要nodejs来获取接口,需要通过ajax来请求数据,实现功能有搜索音乐并显示列表,展示歌词等,本次实现get请求的封装,以及有富含js封装函数的思想,模块化开发状态化处理,说这3个我有点不配啊🤢 只是普通的案例涉及一点这些思想

还是那句话先来效果看下,有点丑,希望大家不要介意🌹🌹🌹 这里吹以下漠河舞厅真的好听

首先运行网易云api,由于是我之前的一个案例,这里忘了在哪里找的api了可以自行查找去下载。安装后打开cmd输入 node app.js运行3000端口

首先准备容器直接放代码 css就不放了有点丑,这里的搜索列表是先通过position隐藏起来的之后在js里再改变其position将其展示(调整top值,让他在页面上面)

<div><input type="text" id="keyword"><button id="search-button">搜索</button></div><!-- 搜索列表 --><div class="search-list"><ul id="result-list"></ul></div><!-- 歌词容器 --><div class="lrc-all-warp"><ul id="lrc-warp"></ul></div><!-- 音频 --><audio src="" id="audio" controls></audio><script src="./music.js"></script>

然后就是最主要的js了

先来封装以下ajax的get请求,因为搜索音乐要频繁的调用ajax请求,每次都调用太过浪费,只在搜素/获取音乐链接的时候发一次,

先放一波常规的ajax请求 发起请求得到数据,将数据修改字符串性质,这里的http://localhost:3000/search?keywords=啦啦啦,简易参考下3000端口的内容,会告诉该怎么获取内容

var xhr =new XMLHttpRequest()// xhr.open('get','http://localhost:3000/search?keywords=啦啦啦',true)// xhr.send()// xhr.onreadystatechange=function(){//if(xhr.status==200&&xhr.readyState==4){// // 获取成功的结果// console.log(JSON.parse(xhr.response))// // 返回的结果是一个JSON的字符串// // 怎么处理JSON格式的字符串// // 变成JS对象数据类型方便我们使用// // 获取音乐名字// var result=JSON.parse(xhr.response)// var songs= result.result.songs// console.log(songs)// // 放歌// var firstSongId=songs[0].Id// xhr.open('get','http://localhost:3000/song/url?id='+firstSongId,true)// xhr.send()//}

接下来就撸起袖子加油干!实现get的ajax请求封装 ,拼接字符串实现 ,url是路径,data是要请求的参数,也就是query参数,callback比较重要,是回调函数,如果调用get方法有回调函数,就会把JSON.parse(xhr.response)当成参数来给该函数。之后的请求会基于这个回调再获取数据,再通过他们的回调获取数据,其实这里有点回调地狱的意思了,我promise没学好,没给他改好,先对付看吧

// get请求包装 把ajax包装成get方法var get = function (url, data, callback) {var xhr = new XMLHttpRequest()var param = '?'for (var key in data) {if (data.hasOwnProperty(key)) {param += key + '=' + data[key] + '&'}}param = param.slice(0, param.length - 1)// http://localhost:3000/song/url?id=123456 要这样的形式 ?id=123456xhr.open('GET', url + param, true)xhr.send()xhr.onreadystatechange = function () {if (xhr.status == 200 && xhr.readyState == 4) {if (callback) {callback(JSON.parse(xhr.response))}}}}

第二层封装,封装一些常用的方法

首先是一个搜索音乐的函数 ,这里就通过给get传递回调函数获取通过请求得到的数据也就是JSON.parse(xhr.response),还有一个回调🐱‍👤,与上面同理,如果存在就把数据通过回调函数传过去

// 建立一个搜索函数var search = function (keywords, callback) {get('http://localhost:3000/search', {keywords: keywords}, function (res) {if (callback) {// 歌在res的result的songs里 此时的res为get()里的callback()里的JSON.parse(xhr.response)callback(res.result.songs)}})}

播放封装

// 播放封装 获取url封装var getSongUrl = function (id, callback) {get('http://localhost:3000/song/url', {id: id}, function (res) {if (callback) {// 音乐播放链接callback(res.data[0].url)}})}

获取歌词封装

var getLrc = function (id, callback) {get('http://localhost:3000/lyric', {id: id}, function (res) {// console.log(res)var lrcString = res.lrc.lyricif (callback) {callback(lrcString)}})}

这些url以及数据都在3000端口有说的

先来俩个简单的函数,打开列表和关闭列表

// 构造打开列表关闭列表方法 用的时候调用就好了var closeSearchList = function () {searchList.className = 'search-list'}var openSearchList = function () {searchList.className = 'search-list active'}

渲染搜索列表方法 这里resultList获取的是渲染列表的ul元素 参数为key也就是到时候输入框获取的value值,并且传递回调函数为参数

使用一个模板来更换ul列表的innerHTML

var resultList = document.getElementById('result-list')var renderSearchList = function (key) {search(key, function (res) {console.log(res)// 模板 class方便点击事件 data-id为了存储歌曲idvar tpl = '<li class="songs" data-id="{--id--}">' +'<h3>{--name--}</h3>' +'<h5><span>{--geshou--}</span> - 专辑:<span>{--zhuanji--}</span></h5>' +'<hr>' +'</li>'var html = ''for (var i = 0; i < res.length; i++) {html += tpl.replace('{--name--}', res[i].name).replace('{--geshou--}', res[i].artists[0].name).replace('{--zhuanji--}', res[i].album.name).replace("{--id--}", res[i].id)}resultList.innerHTML = htmlopenSearchList()// 不要在一个方法构造实现另一个方法// searchList.className='search-list active'addEventListener()})}

这里不直接改变列表的类名来更改样式,而是用了个函数来进行封装,也体现了函数封装的思想,一个代码应该这样他的功能逻辑和函数多少成反比的是。而且这样多的模块可以更好的实现复用以及维护。这才是我这篇文章想向你们表达的东西,更多的实现功能函数,每个方法都是一个函数,达到模块化代码

接下来获取输入框想听的音乐,并且调用获取列表方法展示列表

// 点击按钮 获取Input里的输入值var searchButton = document.getElementById('search-button')var keywordInput = document.getElementById('keyword')searchButton.addEventListener('click', function () {var value = keywordInput.value// 将input的输入值代入renderSearchList函数里renderSearchList(value)})

接下来就是点击列表里的音乐来进行播放了,这里我已经详细把注释写在上面了,这里的songs是之前渲染模板增加的类名,并且把音乐id存储在data-id属性中了,下面的展示歌词和清空歌词下main会说

var audio = document.getElementById('audio')// 做一个li点击事件方法var addEventListener = function () {var songs = document.getElementsByClassName('songs')for (var i = 0; i < songs.length; i++) {songs[i].addEventListener('click', function () {// getAttributevar id = this.getAttribute('data-id')// 通过getSongUrl方法来播放音乐getSongUrl(id, function (url) {// 通过获取audio来播放音乐 通过src来播放audio.src = url// 与视频一样play()开始播放audio.play()closeSearchList()// searchList.className='search-list'})// 展示歌词getLrc(id, function (res) {var lrc = parseLrc(res)console.log(lrc)fillLrc(lrc)})// 清空歌词var lrcWarp = document.getElementById('lrc-warp')if(lrcWarp){lrcWarp.innerHTML=''}})}}

接下来就是解析歌词以及展示歌词了,通过api获取的歌词格式和要使用的歌词有点不太一样,我们得把他解析我们要用的格式,概念写在下面,时间戳是用来到时候来展现歌词高亮用的

[03:06.466]晚星就像你的眼睛杀人又放火\n把字符串转化为数组需要的格式 把字符串准换为对象格式{time:186.466,content:'晚星就像你的眼睛杀人又放火'}

解析歌词方法,方法详细写在了注释上,先把歌词与时间分离开,在格式化时间

// 歌词 // [03:06.466]晚星就像你的眼睛杀人又放火\nvar parseLrc = function (lrcString) {// 将时间字符串类型转化为number类型 做函数var parseTime = function (timeString) {// 切割分钟和秒 会分为俩项var timeStringArr = timeString.split(':') //["01","51.73"]var min = parseInt(timeStringArr[0]) //01var s = parseFloat(timeStringArr[1]) //51.73var totalTime = (min * 60 + s) * 1000return parseInt(totalTime)}var lrcArr = []// 通过split()方法来用'\n'分割歌词lrcArr = lrcString.split('\n')//把每一行存储时间和内容var lrcObjArr = []// 遍历 通过split()方法来用']'分割歌词内容与事件for (var i = 0; i < lrcArr.length; i++) {var lines = lrcArr[i].split(']')//提取时间,通过把 [03:06.466 的 [ 用slice()给切割 得到03:06.466 slice(1,lines[0].length从1开始切(保留)到length最后 仍掉数组[0]var time = parseTime(lines[0].slice(1, lines[0].length))// 内容var content = lines[1]// console.log(time, content)// console.log(lines,time)//错误处理 如果某一行解析不对直接跳过这一行//continue在foreach()里用不了if (content == undefined || isNaN(time)) {continue}lrcObjArr.push({// 因为要把字符串时间转化为数组类型,所以在这里就处理了time: time,content: content})};// console.log(lrcObjArr)return lrcObjArr}

接下来就是封装歌词填充的方法,同样定义模板字符串来拼接通过replace方法来替换

// 模板var tpl = '<li class="lrc-item">{--content--}</li>'// 歌词填充var lrcWarp = document.getElementById('lrc-warp')var fillLrc = function (lrcObjArr) {var html = ''for (var i = 0; i < lrcObjArr.length; i++) {html += tpl.replace('{--content--}', lrcObjArr[i].content)}lrcWarp.innerHTML = htmlnowLrcObject = lrcObjArr}

接下来就是令歌词滚动并且展示高亮了 🐱‍👤都码累了

// 歌词滚动var index = 0// 初始距离var marginTop=240var nowLrcObject = []// 对比歌词var compareLrc = function () {// 在html中获取全部的歌词var lrcItem = document.getElementsByClassName('lrc-item')// 对比时间,确定那一句歌词播放if (nowLrcObject[index].time - audio.currentTime * 1000 < 300) {lrcItem[index].style.color = 'red'// 歌词向上移动20pxmarginTop-=20lrcWarp.style.marginTop=marginTop+'px'lrcItem[index].style.fontSize = '1.2em'// 将上一句的高亮去掉if(index-1>-1){lrcItem[index-1].style.color = ''lrcItem[index-1].style.fontSize = ''}index++}}

最后通过timeupdata事件函数来调用对比歌词方法

// 在这里timeupdate对比audio.addEventListener('timeupdate', function () {compareLrc()})

现在就可以听音乐了!

模块化开发 ,屁大点事也要写个函数 一个函数应该只关心另外一个函数给我们提供的功能,而不参与他的实现。这就是我本篇文章的内容,希望可以得到大家的见解和指摘,感谢大家观看

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。