利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换

网友投稿 186 2023-06-18


利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换

我比较喜欢听音乐,特别是周末的时候,电脑开着百度随心听fm,随机播放歌曲,躺在床上享受。但碰到了一个烦人的事情,想切掉不喜欢的曲子,还得起床去操作电脑换歌。于是思考能不能用手机控制电脑切换歌曲,经过一段事件的思考,绝对采用html5+socket.io来实现这个功能。首先我把该功能的实现拆分为以下几个步骤:

1.移动端前端页面+脚本逻辑实现

2.PC端前端页面+脚本逻辑实现

3.后台逻辑实现

4.加入socket.io实现长连接

5.实现移动端控制PC端逻辑

1、移动端页面脚本的实现

html页面编写

仿造微信摇一摇的页面,实现一个类似的界面,如下所示:

当我们摇手机的时候,会做一个动画,中间的图案一分为二,上半部向上运动然后回来,下半部亦同理,如下所示:

移动端界面

html代码(shake.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-animationmEkMenC: jump 1.5s linear;

animation: jump 1s linear;

}

脚本逻辑

接下来是移动端JS脚本逻辑的实现,摇一摇的实现需借助html5新增的devicemotion事件,获取设备在位置和方向上的改变速度的相关信息,该事件的基本使用如下:

if(window.DeviceMotionEvent){

window.addEventListener('devicemotion',handler,!1);

}else{

alert('你的浏览器不支持摇一摇功能.');

}

devicemotion事件对象中有一个accelerationIncludingGravity属性,该属性包括:一个包含x、y 和z 属性的对象,在考虑z 轴自然重力加速度的情况下,告诉你在每个方向上的加速度。该API的具体使用大家可以参考网上的资料,非常多,这里就不重复了。

摇一摇的具体逻辑如下:

function handler(e){

var current = e.accelerationIncludingGravity;

var currentTime;

var timeDifference;

var deltaX = 0;

var deltaY = 0;

var deltaZ = 0;

//记录上一次设备在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);

//当差距大于设定的阀值并且时间间隔大于指定阀值时,触发摇一摇逻辑

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;

}

由于摇一摇需要播放摇一摇的声音以及切换歌曲成功后的声音,但由于手机大部分是禁止音频的自动播放,必须需要用户真实点击才能播放音频。这里没有彻底的解决办法,只是换了一个思路,利用用户随时触摸屏幕的习惯,对document进行touchstart事件监听。当用户触摸到屏幕时,先播放一个1S的无声音频,接着将touchstart事件移除,然后摇一摇的时候切换声音源,播放摇一摇的声音,这样便可以达到类似的目的。代码如下所示:

document.addEventListener('touchstart',autoplay,!1);

function autoplay(){

shaking.play();

found.play();

document.removeEventListener('touchstart',autoplay);

}

2、PC端前端页面脚本逻辑实现

html文档

PC端界面也是仿的网上的一个html5音乐播放器的界面,效果如下所示:

HTML(shake_pc.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;

}

脚本逻辑

文档加载完成后,随机获取一首音乐,然后播放。点击上一曲或下一曲都是随机切换歌曲,以及可以对音量进行控制,有兴趣的朋友还可以自行实现歌词的同步播放。有关html5媒体原生API,大家可以参考HTML5的Video标签的属性,方法和事件汇总

 部分代码如下:

var mediaEvts =mEkMenC ['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('发生错误');

}

}

};

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元素事件监听

function initMediaEvents(player){

mediaEvts.forEach(function(evt,idx,arr){

var cb = evt+'CB';

player.addEventListener(evt,window[cb],!1);

});

}

3、后台实现

使用express+socket.io实现长连接,socket.io可以利用npm进行安装。根据UA实现PC+移动端渲染不同的页面,将移动端的发送的命令广播给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(`设备${socket.id}断开连接.`);

});

socket.on('message',function(data){

var cmd = data.cmd;

//next命令是由移动端发送,OK命令是由PC切歌成功后发送的命令

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服务器,接着监听事件即可,如下所示:

//移动端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);

});

});

}

当用户摇动设备触发摇一摇时,发送一个next命令的消息给服务端,然后服务端将该消息转发给PC端,PC端接收到该消息后,执行歌曲切换操作,并反馈一个ok命令消息并携带歌曲消息给服务端,服务端再将该消息转发回移动端,移动端播放切歌成功的声音并显示当前PC播放的歌曲。

这个功能主要是我自己使用,可能有些细节没有进行处理,大家可以在该基础上进行改造,还可以做一些多屏互动的效果。

demo下载:http://xiazai.jb51.net/201701/yuanma/shake-music_jb51.rar


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java中流的使用
下一篇:Android性能优化之利用Rxlifecycle解决RxJava内存泄漏详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~