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

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

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

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

3.后台逻辑实现

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

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

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

html页面编写

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

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

移动端界面

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 style="display: none;">
    <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脚本逻辑的实现,摇一摇的实现需借助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)布局代码如下:

<!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 style="display: none;"></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;
		   }

脚本逻辑

文档加载完成后,随机获取一首音乐,然后播放。点击上一曲或下一曲都是随机切换歌曲,以及可以对音量进行控制,有兴趣的朋友还可以自行实现歌词的同步播放。有关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('发生错误');
        }
      }
    };
    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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • HTML5使用DeviceOrientation实现摇一摇功能

    HTML5有一个重要特性:DeviceOrientation,它将底层的方向和运动传感器进行了高级封装,它使我们能够很容易的实现重力感应.指南针等有趣的功能.本文将结合实例给大家介绍使用HTML5的重力运动和方向传感器实现手机摇一摇效果. DeviceOrientation包括两个事件: 1.deviceOrientation:封装了方向传感器数据的事件,可以获取手机静止状态下的方向数据,例如手机所处角度.方位.朝向等. 2.deviceMotion:封装了运动传感器数据的事件,可以获取手机运动

  • javascript html5摇一摇功能的实现

    通过网上的资料,加上自己的整理,写了一份html摇一摇功能的简介,用做技术备份. 知识要点 1.DeviceMotionEvent     这是html5支持的重力感应事件,关于文档请看:http://w3c.github.io/deviceorientation/spec-source-orientation.html 事件介绍: deviceorientation 提供设备的物理方向信息,表示为一系列本地坐标系的旋角. devicemotion 提供设备的加速信息,表示为定义在设备上的坐标系

  • jQuery+HTML5实现手机摇一摇换衣特效

    手机摇一摇可以应用到很多场景中,如摇一摇换抽奖,摇一摇搜歌等.本文我将给大家介绍如何使用HTML5+PHP+jQuery实现手机摇一摇换衣效果. 注意,这是一篇WEB知识综合应用的文章,阅读本文前提是,您需要有HTML5,jQuery,PHP,MySQL等相关方面的基础知识. HTML 我页面中默认展示产品信息(某品牌连衣裙产品图片和文字说明),当然实际应用中可以从数据库中获取产品信息. <div id="pro" rel="1"> <p>使

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

    我比较喜欢听音乐,特别是周末的时候,电脑开着百度随心听fm,随机播放歌曲,躺在床上享受.但碰到了一个烦人的事情,想切掉不喜欢的曲子,还得起床去操作电脑换歌.于是思考能不能用手机控制电脑切换歌曲,经过一段事件的思考,绝对采用html5+socket.io来实现这个功能.首先我把该功能的实现拆分为以下几个步骤: 1.移动端前端页面+脚本逻辑实现 2.PC端前端页面+脚本逻辑实现 3.后台逻辑实现 4.加入socket.io实现长连接 5.实现移动端控制PC端逻辑 1.移动端页面脚本的实现 html页

  • Node.js websocket使用socket.io库实现实时聊天室

    认识websocket WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duple).一开始的握手需要借助HTTP请求完成. 其实websocket 并不是很依赖Http协议,它也拥有自己的一套协议机制,但在这里我们需要利用的socket.io 需要依赖到http . 之前用java jsp写过一个聊天,其实实现逻辑并不难,只是大部分时间都用在UI的设计上,其实现原理就是一个基于websocket的通信,要想做一个好的聊天室,我觉得大部

  • socket.io与pm2(cluster)集群搭配的解决方案

    socket.io与cluster 在线上系统中,需要使用node的多进程模型,我们可以自己实现简易的基于cluster模式的socket分发模型,也可以使用比较稳定的pm2这样进程管理工具.在常规的http服务中,这套模式一切正常,可是一旦server中集成了socket.io服务就会导致ws通道建立失败,即使通过backup的polling方式仍会出现时断时连的现象,因此我们需要解决这种问题,让socket.io充分利用多核. 在这里之所以提到socket.io而未说websocket服务,

  • 使用Angular和Nodejs、socket.io搭建聊天室及多人聊天室

    一,利用Node搭建静态服务器 这个是这个项目的底层支撑部分.用来支持静态资源文件像html, css, gif, jpg, png, javascript, json, plain text等等静态资源的访问.这里面是有一个mime类型的文件映射. mime.js /** * mime类型的 map * @ author Cheng Liufeng * @ date 2014/8/30 * 当请求静态服务器文件的类型 html, css, gif, jpg, png, javascript,

  • iOS + node.js使用Socket.IO框架进行实时通信示例

    Socket.IO是一个基于WebSocket的实时通信库,在主流平台都有很好的支持,此文主要是通过一个小例子来演示Socket.IO的使用. 基础环境搭建 新建一个文件夹(JS工程),创建一个package.json,复制以下内容并保存. { "name": "socket-chat-example", "version": "0.0.1", "description": "my first s

  • node.js中优雅的使用Socket.IO模块的方法

    目录 前言 Socket.IO的定义 Socket.IO的优点 node中安装Socket.IO node中使用Socket.IO emit on 在express中引入使用 服务端 客户端 小结 前言 上篇文章中结合websokcet进行了简单的聊天小案例,但是我们可以发现使用ws模块来写代码的时候未免有一些繁琐,需要我们自己去设置type,使用socket.io后事件监听将会十分的简单便捷,很好的弥补了ws模块的缺陷. Socket.IO的定义 Socket.IO是一个WebSocket库,

  • 基于Nodejs利用socket.io实现多人聊天室

    socket.io简介 在Html5中存在着这样的一个新特性,引入了websocket,关于websocket的内部实现原理可以看这篇文章,这篇文章讲述了websocket无到有,根据协议,分析数据帧的头,进行构建websocket.虽然代码短,但可以很好地体现websocket的原理. ,这个特性提供了浏览器端和服务器端的基于TCP连接的双向通道.但是并不是所有的浏览器都支持websocket特性,故为了磨平浏览器间的差异,为开发者提供统一的接口,引入了socket.io模块.在不支持webs

  • HTML5之WebSocket入门3 -通信模型socket.io

    socket.io为什么会诞生呢?请看下面文字说明. 为什么需要socket.io? node.js提供了高效的服务端运行环境,但是由于浏览器端对HTML5的支持不一,为了兼容所有浏览器,提供卓越的实时的用户体验,并且为程序员提供客户端与服务端一致的编程体验,于是socket.io诞生. socket.io设计的目标是支持任何的浏览器,任何Mobile设备.目前支持主流的PC浏览器(IE,Safari,Chrome,Firefox,Opera等),Mobile浏览器(iphone Safari/

  • Android利用传感器仿微信摇一摇功能

    传感器 简单的介绍一下传感器: 就是设备用来感知周边环境变化的硬件. Android中的传感器包含在传感器框架中,属于android.hardware.*(硬件部分) 传感器框架主要包含四个部分: ① SensorManager:用来获取传感器的入口,它是一个系统的服务,还可以为传感器注册与取消注册监听 ② Sensor: 具体的传感器,包含了传感器的名字,类型,采样率 ③ SensorEvent:传感器事件,包含了传感器采集回来的数据,传感器的精度 ④ SensorEventListener:

随机推荐