用手机来实现远程控制是不是很酷?你不需要去写一个APP应用来实现这种功能,现在的手机浏览器已经支出了web socket技术,这提供了很多的可能。
这篇文章我们将用Node.js和Socket.io来实现手机控制PC的效果。
我们不必到处寻找基于HTML5的这种应用库。我们将使用Reveal.js-它来处理幻灯片动画效果,并支持键盘和触摸事件。
我们不必自己来实现远程控制的接口,我们将实现手机和电脑的同步。这样不仅能控制进度,也能同步的显示在你的手机上。
实现思路
技术上很简单。Reveal.js让当前的幻灯片序号在URL的hash上(e.g. http://example.com/#/1).我们将这个hash发送到所有连接的设备上,
对应的将会根据这个hash来自动的显示响应幻灯片。这样的话,别人可以方便的直接通过url来直接访问到显示的页面,所有我们需要输入一个验证码
在连接之前进行验证。
要说的是Reveal.js已经有一套API,我们可以直接调用来同步。但是hash变化的技术很简单,我们可以直接来实现。
运行
你可以本地运行示例,或者部署到能提供node.js环境的服务器上。本地运行更简单些,但是必须本地有node.js并执行npm install.
运行本地代码
- 下载示例代码
- 确保本地已经安装node.js。如果没有,请安装
- 解压刚才下载的代码包
- 打开终端进入相应的文件夹
- 运行npm install来安装依赖包
- 运行node app.js来启动应用
- PC端在浏览器打开http://localhost:8080,并输入连接码(默认是kittens)
- 在手机端浏览器打开http://
,并输入连接码 - 请享受
代码
思路说完,让我们来看看代码。这主要涉及2个js文件-app.js服务端控制,script.js浏览器端。你可以运行这个应用在Node.js 1.10+或者io.js.
后端,我们用到了express和Socket.io。它主要用来响应socket.io的事件监听。用express.static来让public下的文件可以访问到。
public/index.html文件保护显示的代码。express.static将会让它自动显示,所以我们不需要/来路由。
app.js
- // This is the server-side file of our mobile remote controller app.
- // It initializes socket.io and a new express instance.
- // Start it by running 'node app.js' from your terminal.
- // Creating an express server
- var express = require('express'),app = express();
- // This is needed if the app is run on heroku and other cloud providers:
- var port = process.env.PORT || 8080;
- // Initialize a new socket.io object. It is bound to
- // the express app, which allows them to coexist.
- var io = require('socket.io').listen(app.listen(port));
- // App Configuration
- // Make the files in the public folder available to the world
- app.use(express.static(__dirname + '/public'));
- // This is a secret key that prevents others from opening your presentation
- // and controlling it. Change it to something that only you know.
- var secret = 'kittens';
- // Initialize a new socket.io application
- var presentation = io.on('connection', function (socket) {
- // A new client has come online. Check the secret key and
- // emit a "granted" or "denied" message.
- socket.on('load', function(data){
- socket.emit('access', {
- access: (data.key === secret ? "granted" : "denied")
- });
- });
- // Clients send the 'slide-changed' message whenever they navigate to a new slide.
- socket.on('slide-changed', function(data){
- // Check the secret key again
- if(data.key === secret) {
- // Tell all connected clients to navigate to the new slide
- presentation.emit('navigate', {
- hash: data.hash
- });
- }
- });
- });
- console.log('Your presentation is running on http://localhost:' + port);
下面是前端的js文件,将监听hashchange事件,并发送socket.io消息到服务器端。
public/assets/js/script.js
- $(function() {
- // Apply a CSS filter with our blur class (see our assets/css/styles.css)
- var blurredElements = $('.homebanner, div.reveal').addClass('blur');
- // Initialize the Reveal.js library with the default config options
- // See more here https://github.com/hakimel/reveal.js#configuration
- Reveal.initialize({
- history: true // Every slide will change the URL
- });
- // Connect to the socket
- var socket = io();
- // Variable initialization
- var form = $('form.login'),
- secretTextBox = form.find('input[type=text]');
- var key = "", animationTimeout;
- // When the page is loaded it asks you for a key and sends it to the server
- form.submit(function(e){
- e.preventDefault();
- key = secretTextBox.val().trim();
- // If there is a key, send it to the server-side
- // through the socket.io channel with a 'load' event.
- if(key.length) {
- socket.emit('load', {
- key: key
- });
- }
- });
- // The server will either grant or deny access, depending on the secret key
- socket.on('access', function(data){
- // Check if we have "granted" access.
- // If we do, we can continue with the presentation.
- if(data.access === "granted") {
- // Unblur everything
- blurredElements.removeClass('blurred');
- form.hide();
- var ignore = false;
- $(window).on('hashchange', function(){
- // Notify other clients that we have navigated to a new slide
- // by sending the "slide-changed" message to socket.io
- if(ignore){
- // You will learn more about "ignore" in a bit
- return;
- }
- var hash = window.location.hash;
- socket.emit('slide-changed', {
- hash: hash,
- key: key
- });
- });
- socket.on('navigate', function(data){
- // Another device has changed its slide. Change it in this browser, too:
- window.location.hash = data.hash;
- // The "ignore" variable stops the hash change from
- // triggering our hashchange handler above and sending
- // us into a never-ending cycle.
- ignore = true;
- setInterval(function () {
- ignore = false;
- },100);
- });
- }
- else {
- // Wrong secret key
- clearTimeout(animationTimeout);
- // Addding the "animation" class triggers the CSS keyframe
- // animation that shakes the text input.
- secretTextBox.addClass('denied animation');
- animationTimeout = setTimeout(function(){
- secretTextBox.removeClass('animation');
- }, 1000);
- form.show();
- }
- });
- });
现在是幻灯放映时间
手机远程访问控制已经可以了。希望你能从中得到有趣的体验。这种高端的玩具,还不快点儿操练起来!!