溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

利用HTML5+Socket.io實現(xiàn)搖一搖控制PC端歌曲切換

發(fā)布時間:2020-09-30 12:35:52 來源:腳本之家 閱讀:198 作者:SniffRose 欄目:web開發(fā)

我比較喜歡聽音樂,特別是周末的時候,電腦開著百度隨心聽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)一個類似的界面,如下所示:

利用HTML5+Socket.io實現(xiàn)搖一搖控制PC端歌曲切換

當(dāng)我們搖手機的時候,會做一個動畫,中間的圖案一分為二,上半部向上運動然后回來,下半部亦同理,如下所示:

利用HTML5+Socket.io實現(xiàn)搖一搖控制PC端歌曲切換

移動端界面

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音樂播放器的界面,效果如下所示:

利用HTML5+Socket.io實現(xiàn)搖一搖控制PC端歌曲切換

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í)有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責(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)容。

AI