遙控你的電腦:通過Node.js和Socket.io實(shí)現(xiàn)手機(jī)的遠(yuǎn)程控制
用手機(jī)來實(shí)現(xiàn)遠(yuǎn)程控制是不是很酷?你不需要去寫一個(gè)APP應(yīng)用來實(shí)現(xiàn)這種功能,現(xiàn)在的手機(jī)瀏覽器已經(jīng)支出了web socket技術(shù),這提供了很多的可能。
這篇文章我們將用Node.js和Socket.io來實(shí)現(xiàn)手機(jī)控制PC的效果。
我們不必到處尋找基于HTML5的這種應(yīng)用庫。我們將使用Reveal.js-它來處理幻燈片動(dòng)畫效果,并支持鍵盤和觸摸事件。
我們不必自己來實(shí)現(xiàn)遠(yuǎn)程控制的接口,我們將實(shí)現(xiàn)手機(jī)和電腦的同步。這樣不僅能控制進(jìn)度,也能同步的顯示在你的手機(jī)上。
實(shí)現(xiàn)思路
技術(shù)上很簡(jiǎn)單。Reveal.js讓當(dāng)前的幻燈片序號(hào)在URL的hash上(e.g. http://example.com/#/1).我們將這個(gè)hash發(fā)送到所有連接的設(shè)備上,
對(duì)應(yīng)的將會(huì)根據(jù)這個(gè)hash來自動(dòng)的顯示響應(yīng)幻燈片。這樣的話,別人可以方便的直接通過url來直接訪問到顯示的頁面,所有我們需要輸入一個(gè)驗(yàn)證碼
在連接之前進(jìn)行驗(yàn)證。
要說的是Reveal.js已經(jīng)有一套API,我們可以直接調(diào)用來同步。但是hash變化的技術(shù)很簡(jiǎn)單,我們可以直接來實(shí)現(xiàn)。
運(yùn)行
你可以本地運(yùn)行示例,或者部署到能提供node.js環(huán)境的服務(wù)器上。本地運(yùn)行更簡(jiǎn)單些,但是必須本地有node.js并執(zhí)行npm install.
運(yùn)行本地代碼
- 下載示例代碼
 - 確保本地已經(jīng)安裝node.js。如果沒有,請(qǐng)安裝
 - 解壓剛才下載的代碼包
 - 打開終端進(jìn)入相應(yīng)的文件夾
 - 運(yùn)行npm install來安裝依賴包
 - 運(yùn)行node app.js來啟動(dòng)應(yīng)用
 - PC端在瀏覽器打開http://localhost:8080,并輸入連接碼(默認(rèn)是kittens)
 - 在手機(jī)端瀏覽器打開http://
,并輸入連接碼  - 請(qǐng)享受
 
代碼
思路說完,讓我們來看看代碼。這主要涉及2個(gè)js文件-app.js服務(wù)端控制,script.js瀏覽器端。你可以運(yùn)行這個(gè)應(yīng)用在Node.js 1.10+或者io.js.
后端,我們用到了express和Socket.io。它主要用來響應(yīng)socket.io的事件監(jiān)聽。用express.static來讓public下的文件可以訪問到。
public/index.html文件保護(hù)顯示的代碼。express.static將會(huì)讓它自動(dòng)顯示,所以我們不需要/來路由。
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文件,將監(jiān)聽hashchange事件,并發(fā)送socket.io消息到服務(wù)器端。
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();
 - }
 - });
 - });
 
現(xiàn)在是幻燈放映時(shí)間
手機(jī)遠(yuǎn)程訪問控制已經(jīng)可以了。希望你能從中得到有趣的體驗(yàn)。這種高端的玩具,還不快點(diǎn)兒操練起來!!















 
 
 





 
 
 
 