您好,登錄后才能下訂單哦!
我比較喜歡聽音樂,特別是周末的時候,電腦開著百度隨心聽fm,隨機播放歌曲,躺在床上享受。但碰到了一個煩人的事情,想切掉不喜歡的曲子,還得起床去操作電腦換歌。于是思考能不能用手機控制電腦切換歌曲,經(jīng)過一段事件的思考,絕對采用html5+socket.io來實現(xiàn)這個功能。首先我把該功能的實現(xiàn)拆分為以下幾個步驟:
1.移動端前端頁面+腳本邏輯實現(xiàn)
2.PC端前端頁面+腳本邏輯實現(xiàn)
3.后臺邏輯實現(xiàn)
4.加入socket.io實現(xiàn)長連接
5.實現(xiàn)移動端控制PC端邏輯
1、移動端頁面腳本的實現(xiàn)
html頁面編寫
仿造微信搖一搖的頁面,實現(xiàn)一個類似的界面,如下所示:
當(dāng)我們搖手機的時候,會做一個動畫,中間的圖案一分為二,上半部向上運動然后回來,下半部亦同理,如下所示:
移動端界面
html代碼(shake.html):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no"> <title>搖一搖切歌</title> <link rel="stylesheet" href="shake.css"> </head> <body> <div class="wrap" id="wrap"> <div class="inner"></div> <div class="above-hand hand" id="up"></div> <div class="below-hand hand" id="bt"></div> </div> <div class="tip" id="tip"> </div> <div > <audio id="shaking" src="new_silent.mp3"></audio> <audio id="found" src="new_silent.mp3"></audio> </div> <script type="text/javascript" src="socket.io.js"></script> <script src="shake.js"></script> </body> </html>
樣式表(shake.css):
html,body{ width:100%; height:100%; background-color: #000; margin:0; overflow: hidden; } .wrap{ position: absolute; left:50%; top:50%; width:132px; height: 132px; -webkit-transform: translate(-50%,-50%); transform: translate(-50%,-50%); } .hand{ position: absolute; left:0; width:100%; height: 50%; background: url(shake.png) no-repeat #000; background-size: 132px 132px; } .above-hand{ top:0; background-position: 0 0; } .below-hand{ bottom:0; background-position: 0 -66px; } .inner{ position:absolute; top:50%; left:50%; width: 50px; height: 90px; background: url(inner.png) no-repeat 0 0; background-size: 50px 90px; -webkit-transform: translate(-50%,-50%); transform: translate(-50%,-50%); } .above-hand:after,.below-hand:before{ display: none; content:''; position:absolute; left:-100vw; width:200vw; height: 2px; background-color: #BABDC1; } .above-hand:after{ bottom:0; } .below-hand:before{ top:0; } .wrap.active .above-hand{ -webkit-animation: up 1.5s ease; animation: up 1s ease; } .wrap.active .below-hand{ -webkit-animation: down 1.5s ease; animation: down 1s ease; } .wrap.active .above-hand:after,.wrap.active .below-hand:before{ display: block; } .tip{ position: absolute; bottom: 30px; left: 10px; color: #fff; font-family: '楷體'; text-align: center; right: 10px; height: 32px; line-height: 32px; background-color: rgba(255,255,255,.4); border-radius: 3px; } .tip.active{ -webkit-animation: jump 1.5s linear; animation: jump 1s linear; }
腳本邏輯
接下來是移動端JS腳本邏輯的實現(xiàn),搖一搖的實現(xiàn)需借助html5新增的devicemotion事件,獲取設(shè)備在位置和方向上的改變速度的相關(guān)信息,該事件的基本使用如下:
if(window.DeviceMotionEvent){ window.addEventListener('devicemotion',handler,!1); }else{ alert('你的瀏覽器不支持搖一搖功能.'); }
devicemotion事件對象中有一個accelerationIncludingGravity屬性,該屬性包括:一個包含x、y 和z 屬性的對象,在考慮z 軸自然重力加速度的情況下,告訴你在每個方向上的加速度。該API的具體使用大家可以參考網(wǎng)上的資料,非常多,這里就不重復(fù)了。
搖一搖的具體邏輯如下:
function handler(e){ var current = e.accelerationIncludingGravity; var currentTime; var timeDifference; var deltaX = 0; var deltaY = 0; var deltaZ = 0; //記錄上一次設(shè)備在x,y,z方向上的加速度 if ((lastX === null) && (lastY === null) && (lastZ === null)) { lastX = current.x; lastY = current.y; lastZ = current.z; return; } //得到兩次移動各個方向上的加速度絕對差距 deltaX = Math.abs(lastX - current.x); deltaY = Math.abs(lastY - current.y); deltaZ = Math.abs(lastZ - current.z); //當(dāng)差距大于設(shè)定的閥值并且時間間隔大于指定閥值時,觸發(fā)搖一搖邏輯 if (((deltaX > threshold) && (deltaY > threshold)) || ((deltaX > threshold) && (deltaZ > threshold)) || ((deltaY > threshold) && (deltaZ > threshold))) { currentTime = new Date(); timeDifference = currentTime.getTime() - lastTime.getTime(); if (timeDifference > timeout) { dealShake(); lastTime = new Date(); } } lastX = current.x; lastY = current.y; lastZ = current.z; }
由于搖一搖需要播放搖一搖的聲音以及切換歌曲成功后的聲音,但由于手機大部分是禁止音頻的自動播放,必須需要用戶真實點擊才能播放音頻。這里沒有徹底的解決辦法,只是換了一個思路,利用用戶隨時觸摸屏幕的習(xí)慣,對document進行touchstart事件監(jiān)聽。當(dāng)用戶觸摸到屏幕時,先播放一個1S的無聲音頻,接著將touchstart事件移除,然后搖一搖的時候切換聲音源,播放搖一搖的聲音,這樣便可以達到類似的目的。代碼如下所示:
document.addEventListener('touchstart',autoplay,!1); function autoplay(){ shaking.play(); found.play(); document.removeEventListener('touchstart',autoplay); }
2、PC端前端頁面腳本邏輯實現(xiàn)
html文檔
PC端界面也是仿的網(wǎng)上的一個html5音樂播放器的界面,效果如下所示:
HTML(shake_pc.html)布局代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>隨心聽</title> <meta name="referrer" content="never"> <link rel="stylesheet" href="reset2.0.css"> <link rel="stylesheet" href="shake_pc.css"> </head> <body> <!-- 控制背景圖效果 --> <div class="bg" id="bg"> </div> <div class="music-player"> <!-- 歌曲信息 --> <div class="info"> <div class="song-name" id="songName"></div> <div class="author" id="author">By <span></span></div> <!-- 播放進度 --> <div class="progress" id="progress"></div> </div> <!-- 歌曲控制 --> <div class="controls"> <div class="time" id="time">00:00</div> <div class="play-controls"> <a href="javascript:;" class="prev btn" id="prev"> </a><a href="javascript:;" class="play btn" id="play"> </a><a href="javascript:;" class="next btn" id="next"></a> </div> <div class="volume-bar"> <a href="javascript:;" class="vol-muted" id="muted"> </a><a href="javascript:;" class="vol-slider" id="volSilder"> <span class="vol-slider-inner" id="volInner"></span> </a><a href="javascript:;" class="vol-max" id="volMax"></a> </div> </div> <!-- 歌曲播放 --> <audio id="audio" controls ></audio> </div> <script type="text/javascript" src="socket.io.js"></script> <script type="text/javascript" src="shake_pc.js"></script> </body> </html>
css樣式
樣式布局非常的簡單,沒什么好講的。CSS樣式代碼(shake_pc.css)如下:
body{ font-family: 'Open Sans', sans-serif; overflow: hidden; } .bg{ position: absolute; left:0; right: 0;top:0; bottom: 0;margin:-30px; filter: blur(30px); -webkit-filter: blur(30px); background: url(./imgaes/bg.jpg) no-repeat; background-size: cover; } .music-player{ position: relative; width: 350px; height: 290px; margin: 150px auto; box-shadow: 0 0 60px rgba(0, 0, 0, 0.8); border-radius: 7px; background: #222; overflow: hidden; z-index: 0; } .info{ position: relative; width: 100%; height: 80px; padding-top: 20px; color:#585858; text-align: center; } .info .song-name{ height: 30px; font-size: 30px; font-weight: 300; } .info .author{ margin-top: 14px; font-size: 14px; } .progress{ position: absolute; left:0; bottom:0; width: 0; height: 3px; background-color: #ed553b; } .controls{ height: 190px; background-color:rgba(152, 46, 75, 0.6); text-align: center; } .controls .time{ font-size:48px; height: 84px; line-height: 84px; color:rgba(225, 225, 225, 0.4); } .play-controls .btn{ display: inline-block; width:95px; height: 40px; vertical-align: top; } .play-controls .btn.prev{ background:url(./imgaes/prev.png) no-repeat center center; } .play-controls .btn.play{ background:url(./imgaes/play.png) no-repeat center center; } .play-controls .btn.next{ background:url(./imgaes/next.png) no-repeat center center; } .volume-bar{ position: relative; width:250px; height: 2px; margin: 30px auto 0; } .volume-bar .vol-muted{ position:absolute; left:0; top:-6px; width: 10px; height:13px; background:url(./imgaes/muted.png) no-repeat center center; } .volume-bar .vol-slider{ position: absolute; left:14px; right:28px; top:0; height:100%; background-color:rgba(255,255,255,.3); } .volume-bar .vol-slider-inner{ display: block; width:50%; height: 100%; background-color:#ed553b; } .volume-bar .vol-max{ position:absolute; right:0; top:-8.5px; width: 22px; height: 18px; background: url(./imgaes/max.png) no-repeat center center; }
腳本邏輯
文檔加載完成后,隨機獲取一首音樂,然后播放。點擊上一曲或下一曲都是隨機切換歌曲,以及可以對音量進行控制,有興趣的朋友還可以自行實現(xiàn)歌詞的同步播放。有關(guān)html5媒體原生API,大家可以參考HTML5的Video標簽的屬性,方法和事件匯總
部分代碼如下:
var mediaEvts = ['loadedmetadata','ended','timeupdate','error']; //隨機獲取一首音樂 function getSong(){ return new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.responseText); }else{ reject('發(fā)生錯誤'); } } }; xhr.open('get', 'http://api.jirengu.com/fm/getSong.php?channel=1', !0); xhr.send(); }); } function dealSong(responseText){ var songObj = JSON.parse(responseText), song = songObj.song[0]; updateUI(song); setMedia(song); return song; } function setMedia(song){ var songSrc = song.url, lrc = song.lrc; player.src = songSrc; player.volume = 0.5; player.play(); } function updateUI(song){ var name = song.title, artist = song.artist, img = song.picture; songName.innerText = name; author.querySelector('span').innerText = artist; bg.style.backgroundImage = 'url('+img+')'; } //初始化audio元素事件監(jiān)聽 function initMediaEvents(player){ mediaEvts.forEach(function(evt,idx,arr){ var cb = evt+'CB'; player.addEventListener(evt,window[cb],!1); }); }
3、后臺實現(xiàn)
使用express+socket.io實現(xiàn)長連接,socket.io可以利用npm進行安裝。根據(jù)UA實現(xiàn)PC+移動端渲染不同的頁面,將移動端的發(fā)送的命令廣播給PC端,然后達到移動端控制PC的效果,代碼如下所示:
const http = require('http'); var express = require('express'); var app = express(); var server = require('http').Server(app); var io = require('socket.io')(server); app.use(express.static('./')); app.get('/',(req,res)=>{ var userAgent = req.headers['user-agent'].toLowerCase(); if(/(android|iphone|mobile)/.test(userAgent)){ res.sendFile(__dirname+'/shake_m.html'); }else{ res.sendFile(__dirname+'/shake_pc.html'); } }); io.on('connection',function(socket){ var usrname = '', sendData = {}; console.log('a client connect...'+socket.id); socket.on('disconnect',function(){ console.log(`設(shè)備${socket.id}斷開連接.`); }); socket.on('message',function(data){ var cmd = data.cmd; //next命令是由移動端發(fā)送,OK命令是由PC切歌成功后發(fā)送的命令 if(cmd == 'next'){ socket.broadcast.emit('next'); }else if(cmd == 'ok'){ socket.broadcast.emit('ok',data.data); } }); }); server.listen(3000,function(){ console.log('start listening on 3000 port...'); });
4、移動端和PC端加上socket.io
首先在頁面中引入socket.io.js,然后連接socket服務(wù)器,接著監(jiān)聽事件即可,如下所示:
//移動端socket邏輯 socket.on('connect',function(){ console.log('websocket連接已建立...'); }); socket.on('ok',function(data){ if(found.src!=host+'found.mp3'){ found.src = 'found.mp3'; } found.play(); tip.innerText = '正在欣賞:'+data.artist+'--'+data.title; tip.classList.remove('active'); tip.offsetWidth = tip.offsetWidth; tip.classList.add('active'); }); function dealShake(){ if(isShaking) return; isShaking = !0; if(shaking.src!=host+'shaking.mp3'){ shaking.src = 'shaking.mp3'; } shaking.play(); wrap.classList.add('active'); setTimeout(function(){ socket.emit('message',{cmd:'next',data:null}); },1000); } //PC端socket邏輯 function initIOEvts(){ socket.on('connect',function(){ console.log('websocket連接已建立...'); }); socket.on('next',function(data){ getSong().then(function(val){ var song = dealSong(val); socket.emit('message',{cmd:'ok',data:song}); },function(err){ console.log(err); }); }); }
當(dāng)用戶搖動設(shè)備觸發(fā)搖一搖時,發(fā)送一個next命令的消息給服務(wù)端,然后服務(wù)端將該消息轉(zhuǎn)發(fā)給PC端,PC端接收到該消息后,執(zhí)行歌曲切換操作,并反饋一個ok命令消息并攜帶歌曲消息給服務(wù)端,服務(wù)端再將該消息轉(zhuǎn)發(fā)回移動端,移動端播放切歌成功的聲音并顯示當(dāng)前PC播放的歌曲。
這個功能主要是我自己使用,可能有些細節(jié)沒有進行處理,大家可以在該基礎(chǔ)上進行改造,還可以做一些多屏互動的效果。
demo下載:http://xiazai.jb51.net/201701/yuanma/shake-music_jb51.rar
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。