Electron使用介紹

[轉(zhuǎn)載自http://get.ftqq.com/7870.get]

<html lang="zh-cmn-Hans">

<head>

<meta charset="utf-8">

<meta property="wb:webmaster" content="6fb2b4de5a6b35cc" />

<link rel="icon"

type="image/png"

href="/static/image/get32px.png">

<title>用Electron開發(fā)桌面應(yīng)用 | @Get社區(qū)</title>

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link href="/static/css/bootstrap.min.css" rel="stylesheet">

<link rel="stylesheet" href="/static/css/app.css?v=2014" type="text/css" >

<link rel="stylesheet" href="/static/css/jdc.icon.css?v=2014" type="text/css" >

<link rel="stylesheet" href="/static/css/jquery.jscrollpane.css" type="text/css" >

<link rel="stylesheet" href="/static/css/../components/jquery.atwho/dist/css/jquery.atwho.min.css" type="text/css" >

<link rel="stylesheet" type="text/css" >

<link rel="stylesheet" type="text/css" href="/static/css/yue.css">

<link rel="stylesheet" type="text/css" href="/static/css/article-btn.css">

<link rel="stylesheet" type="text/css" href="/static/css/imgshare.css">

<script src="http://cdn.staticfile.org/jquery/2.2.1/jquery.min.js"></script>

<script src="/static/script/bootstrap.min.js"></script>

<script src="/static/script/jquery.jscrollpane.min.js"></script>

<script src="/static/script/jquery.mousewheel.js"></script>

<script src="/static/script/../components/notifyjs/dist/notify-combined.min.js"></script>

<script src="/static/script/../components/jquery.onoff/dist/jquery.onoff.min.js"></script>

<script src="/static/script/../components/jquery.atwho/dist/js/jquery.atwho.min.js"></script>

<script src="/static/script/../components/Caret.js/dist/jquery.caret.min.js"></script>

<script src="/static/script/../components/jquery-waypoints/waypoints.min.js"></script>

<script src="http://cdn.staticfile.org/highlight.js/9.0.0/highlight.min.js"></script>

<script src="/static/script/app.js"></script>

<script type="text/javascript" src="/static/script/jquery.imgshare.js" ></script>

<script type="text/javascript" src="/static/script/timeago.js" ></script>

<script type="text/javascript" src="/static/script/locales/timeago.zh-cn.js" ></script>

<script>

window.zhuge = window.zhuge || [];

window.zhuge.methods = "_init debug identify track trackLink trackForm page".split(" ");

window.zhuge.factory = function(b) {

return function() {

var a = Array.prototype.slice.call(arguments);

a.unshift(b);

window.zhuge.push(a);

return window.zhuge

}

};

for (var i = 0; i < window.zhuge.methods.length; i++) {

var key = window.zhuge.methods[i];

window.zhuge[key] = window.zhuge.factory(key)

}

window.zhuge.load = function(b, x) {

if (!document.getElementById("zhuge-js")) {

var a = document.createElement("script");

var verDate = new Date();

var verStr = verDate.getFullYear().toString()

  • verDate.getMonth().toString() + verDate.getDate().toString();

a.type = "text/javascript";

a.id = "zhuge-js";

a.async = !0;

a.src = (location.protocol == 'http:' ? "http://sdk.zhugeio.com/zhuge-lastest.min.js?v=" : 'https://zgsdk.zhugeio.com/zhuge-lastest.min.js?v=') + verStr;

var c = document.getElementsByTagName("script")[0];

c.parentNode.insertBefore(a, c);

window.zhuge._init(b, x)

}

};

window.zhuge.load('e1189bf28dd14a39a2f72b3a47abc3b7');

</script>

</head>

<body id="body">

<div class="navbar navbar-fixed-top navbar-get" role="navigation" id="theheader">

<div class="container clearfix">

<a class="logo" href="/?c=default">

<span class="get">Get</span>社區(qū)</a> <div class="new_message_notice"></div>

<div class="navbar-collapse collapse pull-right">

<ul class="get-cate-nav">

<li class="dropdown active ">

<button class="btn btn-getnar dropdown-toggle" type="button" onclick="location='/?c=default'">

新知

</button>

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">

<li class=""><a href="/">全部</a></li>

<li class="" role="presentation"><a href="/?cate=1" role="menuitem" tabindex="-1">技術(shù)</a></li>

<li class="" role="presentation"><a href="/?cate=2" role="menuitem" tabindex="-1">設(shè)計</a></li>

<li class="" role="presentation"><a href="/?cate=3" role="menuitem" tabindex="-1">產(chǎn)品</a></li>

<li class="" role="presentation"><a href="/?cate=4" role="menuitem" tabindex="-1">創(chuàng)業(yè)</a></li>

<li class=""><a href="/?a=kb">我的</a></li>

<li class=""><a href="/?a=feed">我關(guān)注的</a></li>

<li class="" ><a href="/?a=submit" target="_blank">+添加新知</a></li>

</ul>

</li>

<li class="dropdown ">

<button class="btn btn-getnar dropdown-toggle" type="button" onclick="location='/?c=card'">

卡片流

</button>

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">

<li class=""><a href="/?c=card">我的首頁</a></li>

<li class=""><a href="/?c=card&a=explore">隨便看看</a></li>

</ul>

</li>

</ul>

</div>

</div>

</div>

<div class="container">

<div class="row row-offcanvas row-offcanvas-right">

<div class="col-xs-12 col-sm-9">

<div class="get-article-area " id="gacontent">

<h2 class="green">用Electron開發(fā)桌面應(yīng)用</h2>

<p class="exp">用JavaScript浮创,Node.js和Eletron創(chuàng)建發(fā)聲器應(yīng)用的詳細指南</p>

<div class="yue top20">

<blockquote><p>本文主要介紹了如何用Electron配合JavaScript等web技術(shù)創(chuàng)建桌面應(yīng)用秘蛔。
</p><p>由 <a target="_blank">Bazzzinga威</a> 同學(xué)翻譯自 Medium。<a >https://medium.com/developers-writing/building-a-desktop-application-with-electron-204203eeb658</a>
</p></blockquote><h1>什么是JavaScript桌面應(yīng)用</h1><p>在我心中磅氨,桌面應(yīng)用一直占據(jù)著一個特殊的地位炼蛤。隨著瀏覽器悯周,移動設(shè)備變得越來越強大闻葵,被移動和web應(yīng)用取代的桌面應(yīng)用呈穩(wěn)定下滑趨勢晃虫。但編寫桌面應(yīng)用還是有很多優(yōu)勢的--它們會一直存在于你的開始目錄或者Dock欄中荠商,可以被alt(cmd)+tab來回切換寂恬,并且大部分比web應(yīng)用與底層系統(tǒng)聯(lián)系的更緊密(快捷鍵,通知推送等)莱没。</p><p>本文中初肉,我會引導(dǎo)你用JavaScript創(chuàng)建一個簡單桌面應(yīng)用,接觸相關(guān)的概念饰躲。</p><p>

</p><p>用JavaScript編寫桌面應(yīng)用的核心思想是編寫一套資料庫牙咏,把它分別打包來兼容各個操作系統(tǒng)。不需要創(chuàng)建原生桌面應(yīng)用的知識嘹裂,維護起來更簡單⊥現(xiàn)在,用JavaScript開發(fā)桌面應(yīng)用主要是使用<a target="_blank">Electron</a>或者<a target="_blank">NW.js</a>寄狼。盡管兩種工具提供的功能相似丁寄,我更喜歡Electron,因為它有一些我認為<a target="_blank">很重要的優(yōu)勢</a>。到頭來伊磺,你用哪一個都沒有問題盛正。</p><p></p><h1><b>基本假定</b></h1><p>我假定你已經(jīng)有了文本編輯器(或者IDE),并且安裝了<a target="_blank">Node.js和npm</a>奢浑。同樣假定你已經(jīng)掌握HTML/CSS/JavaScript的知識(如果會Node.js和CommonJS模塊更好蛮艰,不過并不是必需的),這樣可以將重點放在學(xué)習(xí)Electron雀彼,而不需要擔心創(chuàng)建用戶界面(其實就是普通的web頁面)壤蚜。如果你不符合前面幾點,你也許會感到有些迷惑徊哑,我推薦你看下<a target="_blank">我的前一篇文章</a>來學(xué)習(xí)基礎(chǔ)袜刷。</p><p></p><p></p><h1><b>Electron 概述</b></h1><p>簡單來說,Electron為用純JavaScript創(chuàng)建桌面應(yīng)用提供了運行時莺丑。原理是著蟹,Electron調(diào)用你在package.json中定義的main文件并執(zhí)行它。main文件(通常被命名為main.js)會創(chuàng)建一個內(nèi)含渲染完的web頁面的應(yīng)用窗口梢莽,并添加與你操作系統(tǒng)的原生GUI(圖形界面)交互的功能萧豆。</p><p>詳細地說,當用Electron啟動一個應(yīng)用昏名,會創(chuàng)建一個主進程涮雷。這個主進程負責與你系統(tǒng)原生的GUI進行交互并為你的應(yīng)用創(chuàng)建GUI(在你的應(yīng)用窗口)。</p><p></p><p>
</p><p></p><p>僅啟動主進程并不能給你的應(yīng)用用戶創(chuàng)建應(yīng)用窗口轻局。窗口是通過main文件里的主進程調(diào)用叫BrowserWindow的模塊創(chuàng)建的洪鸭。每個瀏覽器窗口會運行自己的渲染進程。渲染進程會在窗口中渲染出web頁面(引用了CSS仑扑,JavaScript览爵,圖片等的HTML文件)。web頁面是<a target="_blank">Chromium</a>渲染的镇饮,因為各系統(tǒng)下標準是統(tǒng)一的的蜓竹,所以兼容性很好。</p><p>舉例來說盒让,如果你有一個計算器應(yīng)用梅肤,主進程會初始化一個窗口來呈現(xiàn)實際的web頁面(計算器)。</p><p></p><p></p><p>雖說只有主進程才和系統(tǒng)原生GUI交互邑茄,還是有技術(shù)可以把部分任務(wù)轉(zhuǎn)到渲染進程中運行姨蝴。</p><p>主進程通過一套<a target="_blank">可直接調(diào)用的Electron模塊</a>與原生GUI交互,桌面應(yīng)用可以使用所有的Node模塊肺缕,如用<a target="_blank">node-notifier模塊</a>來推送系統(tǒng)通知左医,<a target="_blank">request模塊</a>來發(fā)起HTTP請求等授帕。</p>
<h1>Hello, world!</h1><h2><b>練習(xí)用資料庫</b>
</h2><p>現(xiàn)在,讓我們做好準備浮梢,用傳統(tǒng)的「Hello跛十,World」來開始。</p><p>本指南的同步練習(xí)資料庫是<a target="_blank">sound-machine-tutorial</a>秕硝。首先把資料庫clone下來:</p><p></p><pre class="">git clone <a rel="nofollow">https://github.com/bojzi/sound-machine-electron-guide.git</a></pre><p>進入sound-machine-tutorial文件夾芥映,用下面的代碼在git的tag之間切換:</p><pre class="">git checkout <tag-name></pre><p>我會提示你該用哪個tag:</p><pre class="">請切換至:
git checkout 00-blank-repository</pre><p>當你clone完代碼,切換到你想要的tag远豺,運行:</p><pre class="">npm install</pre><p></p><p>這樣你安裝好全部Node模塊了奈偏。</p><p>如果你不能轉(zhuǎn)換到另一個tag,最簡單的辦法是重置你的資料庫狀態(tài)再切換:</p><p></p><pre class="">git add -A
git reset --hard</pre><p><b>開始</b></p><pre class="">請切換到00-blank-repository這個tag:
git checkout 00-blank-repository</pre><p>在項目文件夾中新建package.json文件躯护,寫入下面的內(nèi)容:</p><p></p><p>這個簡單的package.json文件:</p><ul><li>設(shè)置應(yīng)用的名字和版本號惊来,</li><li>設(shè)置Electron主進程運行的腳本(main.js),</li><li>設(shè)置一個很實用的快捷鍵--在你的CLI(命令行)中可以用「npm start」方便地啟動應(yīng)用棺滞。</li></ul><p>現(xiàn)在該安裝Electron了裁蚁,最簡單的方式是用npm為你的操作系統(tǒng)安裝預(yù)構(gòu)建的二進制文件。并在package.json文件中將它設(shè)置為開發(fā)依賴(用--save-dev命令后綴自動設(shè)置)继准。在CLI中運行命令:</p><pre class="">npm install --save-dev electron-prebuilt</pre><p></p><p>預(yù)構(gòu)建的二進制文件是為所在的操作系統(tǒng)量身訂造的枉证,可以運行「npm start」。我們將它作為開發(fā)依賴安裝是因為只在開發(fā)過程中用到它移必。</p><p></p><p>就這樣刽严,Electron開發(fā)所需的一切都準備好了。</p><h2><b>跟世界打個招呼</b></h2><p>新建app文件夾避凝,在其中新建有下面代碼的index.html文件:</p><pre class=""><h1>Hello, world!</h1></pre><p></p><p>在項目的根目錄下新建一個main.js文件。Electron的主進程將用它來啟動并創(chuàng)建「Hello, world」桌面應(yīng)用眨补。main.js中的代碼:</p><pre class="">'use strict';

var app = require('app');

var BrowserWindow = require('browser-window');

var mainWindow = null;

app.on('ready', function() {

mainWindow = new BrowserWindow({

height: 600,

width: 800

});

mainWindow.loadUrl('file://' + __dirname + '/app/index.html');

});

</pre><p></p><p>沒什么嚇人的管削,不是嗎?</p><p>「app」模塊會控制應(yīng)用的生命周期(例如撑螺, 對應(yīng)用的ready狀態(tài)做出反應(yīng))含思。</p><p>「BrowserWindow」模塊為你創(chuàng)建窗口。</p><p>「mainWindow」對象是你應(yīng)用的主窗口甘晤,被聲明成null含潘,否則當JavaScript垃圾回收掉這個對象時,窗口會被關(guān)閉线婚。</p><p>當「app」捕獲ready事件遏弱,「BrowserWindow」創(chuàng)建一個800*600大小的窗口。</p><p>瀏覽器窗口的渲染進程會渲染index.html文件塞弊。</p><p>在CLI中鍵入下面命令啟動「Hello, World!」:</p><p></p><pre class="">npm start</pre><p>現(xiàn)在為你的第一個Electron程序歡呼吧漱逸。</p><p>

</p><p>
</p>
<p></p><h1>開發(fā)真正的應(yīng)用</h1><h2><b>超棒的發(fā)聲器</b></h2><p>首先泪姨,什么是發(fā)聲器?</p><p>發(fā)聲器當你點擊不同按鈕時會播放不同聲音的小設(shè)備饰抒,大部分是卡通或特效聲肮砾。是在辦公室用來放松心情的,很有趣的工具袋坑,隨著開發(fā)的進行仗处,會碰到的很多新的概念,所以這也是一個很好的開發(fā)桌面應(yīng)用的實例(也是一個非常棒的發(fā)聲器)枣宫。</p><p></p><p>
</p><p>我們將完成的功能和探索的概念包括:</p><ul><li>基礎(chǔ)發(fā)聲器(基本的瀏覽器窗口初始化)婆誓,</li><li>關(guān)閉發(fā)聲器(在主進程和渲染進程之間遠程通信),</li><li>不需要把焦點切到應(yīng)用就可以播放聲音(全局快捷鍵)镶柱,</li><li>創(chuàng)建快捷鍵的設(shè)定界面旷档,來變更鍵位(Shift,Ctrl和Alt)(保存在用戶的個人文件夾設(shè)置中)歇拆,</li><li>加一個托盤圖標(遠程創(chuàng)建原生GUI元素鞋屈,了解菜單和托盤圖標),</li><li>打包你的應(yīng)用(把你的應(yīng)用打包成 Mac故觅,Windows厂庇,Linux下可用的版本)。</li></ul>
<h2>實現(xiàn)發(fā)聲器的基礎(chǔ)功能</h2><p><b>應(yīng)用的結(jié)構(gòu)</b></p><p></p><p>你已經(jīng)實現(xiàn)了一個運行正常的「Hello World!」應(yīng)用输吏,現(xiàn)在是時候?qū)崿F(xiàn)一個發(fā)聲器應(yīng)用了权旷。</p><p>典型的發(fā)聲器功能包括幾排按鈕,點擊播放聲音贯溅,這些聲音大部分是卡通式的或者特效式的(如大笑拄氯,鼓掌,玻璃碎裂聲等)它浅。</p><p>那就是我們要完成的第一個功能--能對點擊能做出響應(yīng)的發(fā)聲器译柏。</p><p>
</p><p></p><p>應(yīng)用結(jié)構(gòu)是比較簡單的。</p><p>在應(yīng)用的根目錄姐霍,保存著package.json文件鄙麦,main.js文件和其他文件。</p><p>app文件夾保存HTML文件镊折,其中在css胯府,js,wav和img文件夾中保存相應(yīng)類型的文件恨胚。</p><p>為了簡便骂因,web頁面所需的全部文件都已經(jīng)保存在資料庫的初始狀態(tài)中。現(xiàn)在切換到01-start-project這個tag赃泡。如果你之前跟著指南操做侣签,創(chuàng)建了「Hello World!」應(yīng)用塘装,你需要先重置資料庫再切換:</p><p></p><pre class="">If you followed along with the "Hello, world!" example:
git add -A
git reset --hard</pre><pre class="">切換到01-start-project這個tag:
git checkout 01-start-project</pre><p></p><p>為了簡便,發(fā)聲器將只有兩種聲音影所,但擴展到全部16種聲音也非常簡單蹦肴,只需要其他聲音和圖標文件,修改index.html就可以猴娩。</p><p><b>完成主進程</b></p><p>用main.js定義發(fā)聲器的外觀阴幌。用下面的代碼代替原內(nèi)容:</p><pre class="">'use strict';

var app = require('app');

var BrowserWindow = require('browser-window');

var mainWindow = null;

app.on('ready', function() {

mainWindow = new BrowserWindow({

frame: false,

height: 700,

resizable: false,

width: 368

});

mainWindow.loadUrl('file://' + __dirname + '/app/index.html');

});

</pre><p></p><p></p><p>我們用傳給「app」模塊的尺寸參數(shù),自定義了新建窗口的大小卷中,設(shè)定它是固定尺寸并且無邊欄矛双。它會浮在你的桌面上,就像真的發(fā)聲機一樣蟆豫。</p><p>現(xiàn)在的問題是 -- 如何移動一個沒有邊欄的窗口(沒有標題欄)议忽,如何關(guān)閉它?</p><p>我很快就會講解自定義窗口(應(yīng)用)關(guān)閉(并介紹一種主進程和渲染進程通信的方法)十减,但拖動部分很簡單栈幸,在index.css(app/css文件夾下)文件中:</p><p></p><pre class="">html,

body {

...

-webkit-app-region: drag;

...

}

</pre><p>-webkit-app-region:drag;使整個html變成一個可拖動的對象。現(xiàn)在有一個問題帮辟,你不能點擊可拖動對象里的按鈕速址。答案就是-webkit-app-region: no-drag;能定義不可拖動(但是可以點擊)的對象,參考index.css的中的代碼:</p><pre class="">.button-sound {

...

-webkit-app-region: no-drag;

}

</pre><p><b>在窗口中顯示發(fā)聲器</b></p><p></p><p>main.js文件現(xiàn)在可以新建一個窗口來顯示發(fā)聲器由驹。如果用npm start啟動應(yīng)用逢防,你可以看到發(fā)聲器非常逼真〖酪現(xiàn)在點擊沒有反應(yīng)炉菲,這并不奇怪他嚷,我們只有一個靜態(tài)的web頁面。</p><p>添加下面的代碼到index.js(app/js文件夾)文件中會添加交互效果:</p><p></p><pre class="">'use strict';

var soundButtons = document.querySelectorAll('.button-sound');

for (var i = 0; i < soundButtons.length; i++) {

var soundButton = soundButtons[i];

var soundName = soundButton.attributes['data-sound'].value;

prepareButton(soundButton, soundName);

}

function prepareButton(buttonEl, soundName) {

buttonEl.querySelector('span').style.backgroundImage = 'url("img/icons/' + soundName + '.png")';

var audio = new Audio(__dirname + '/wav/' + soundName + '.wav');

buttonEl.addEventListener('click', function () {

audio.currentTime = 0;

audio.play();

});

}

</pre><p></p><p>代碼很簡單甥郑,我們:</p><ul><li>查詢所有聲音按鈕渣触,</li><li>遍歷所有的按鈕讀取data-sound屬性,</li><li>給每個按鈕加背景圖壹若,</li><li>給每個按鈕加一個點擊事件來播放音頻(調(diào)用<a target="_blank">HTML AudioElement接口</a>)</li></ul><p>CLI中輸入下面命令來測試應(yīng)用:</p><p></p><pre class="">npm start</pre><p>

</p><p>
</p>
<h2>用遠程事件從瀏覽器窗口關(guān)閉應(yīng)用</h2><pre class="">請切換到02-basic-sound-machine這個tag:
git checkout 02-basic-sound-machine</pre><p>簡要重述--應(yīng)用窗口(更準確的說是渲染進程)應(yīng)該不能與GUI(用來關(guān)閉窗口)通信的,官方的<a target="_blank">Electron快速入門指南</a>寫到:</p><blockquote>在web頁面皂冰,不允許調(diào)用原生GUI相關(guān)的API店展,因為在web頁面管理原生GUI資源是很危險的,會很容易泄露資源秃流。如果你想在web頁面施行GUI操作赂蕴,web頁面的渲染進程必須要與主進程通信,請求主進程來完成這些操作舶胀。</blockquote><p>Electron提供<a target="_blank">ipc(進程間通信)模塊</a>來實現(xiàn)這類通信概说。ipc模塊可實現(xiàn)從通道訂閱消息碧注,發(fā)送消息給通道的訂閱者,通道區(qū)分消息的接收者糖赔,用字符來標識(例如萍丐,通道1,通道2)放典。消息也可以包含數(shù)據(jù)逝变。當接收到消息,訂閱者可以做出反應(yīng)奋构,甚至回復(fù)消息壳影。消息最大的好處就是隔離 -- 主進程不必知道哪個渲染進程發(fā)出消息。</p><p>
</p><p></p><p>這正是我們在做的 -- 主進程(main.js)訂閱「close-main-window」通道的消息弥臼,關(guān)閉按鈕被點擊時宴咧,渲染進程(index.js)通過通道發(fā)出消息。</p><p>在main.js里添加下面的代碼径缅,從通道訂閱消息:</p><p></p><pre class="">var ipc = require('ipc');

ipc.on('close-main-window', function () {

app.quit();

});

</pre><p></p><p>引入ipc模塊后掺栅,通過通道訂閱消息就變得很簡單,on()方法設(shè)置訂閱的通道名芥驳,定義回調(diào)函數(shù)柿冲。</p><p>渲染進程要通過通道發(fā)送消息,將下面代碼加入index.js:</p><pre class="">var ipc = require('ipc');

var closeEl = document.querySelector('.close');

closeEl.addEventListener('click', function () {

ipc.send('close-main-window');

});

</pre><p></p><p></p><p>同樣兆旬,我們引入ipc模塊假抄,給關(guān)閉按鈕的元素綁定一個click事件。當點擊關(guān)閉按鈕時丽猬,通過「close-main-window」通道的send()方法發(fā)送消息宿饱。</p><p>這里還有個小問題,如果不注意會卡住你脚祟,我們已經(jīng)討論過--可拖動區(qū)域的可點擊性谬以。index.css需要把關(guān)閉按鈕定義成不可拖動:</p><pre class="">.settings {

...

-webkit-app-region: no-drag;

}

</pre><p></p><p>就這樣,現(xiàn)在可以點擊關(guān)閉按鈕關(guān)閉我們的應(yīng)用了由桌。因為要監(jiān)聽事件或傳遞參數(shù)为黎,通過ipc模塊通信比較復(fù)雜。我們后面會看到一個傳遞參數(shù)的例子行您。</p>


<h2>用全局快捷鍵播放聲音</h2><pre class="">請切換到名為03-closable-sound-machine的tag:
git checkout 03-closable-sound-machine</pre><p></p><p>基礎(chǔ)的發(fā)聲器工作順利铭乾,但是我們有一個易用性問題--如果發(fā)聲器一定需要切到應(yīng)用窗口,再點擊才能播放娃循,這個發(fā)聲器有什么用炕檩?</p><p>這時我們需要的就是全局快捷鍵。Electron提供一個<a target="_blank">全局快捷鍵模塊</a>捌斧,允許你監(jiān)聽自定義的鍵盤組合并做出反應(yīng)笛质。鍵盤組合也被叫做<a target="_blank">加速器</a>泉沾,是一系列鍵盤點擊組成的字符串(例如 “Ctrl+Shift+1”)。</p><p></p><p>
</p><p></p><p>既然我們想要捕捉一個原生GUI事件(全局快捷鍵)妇押,然后在應(yīng)用窗口做出反應(yīng)(播放聲音)跷究,我們?nèi)杂胕pc模塊在主進程和渲染進程之間通信。</p><p>在深入到代碼層面前舆吮,有兩件事要考慮:</p><ol><li>全局快捷鍵應(yīng)在app的「ready」事件觸發(fā)后被注冊(在ready代碼塊中)揭朝,</li><li>當通過ipc從主進程發(fā)送消息到渲染進程的時候,你要引用到那個窗口(就像「createWindow.webContent.send('channel')」)</li></ol><p>記住這些色冀,現(xiàn)在用下面的代碼來修改我們的main.js文件:</p><pre class="">var globalShortcut = require('global-shortcut');

app.on('ready', function() {

... // existing code from earlier

globalShortcut.register('ctrl+shift+1', function () {

mainWindow.webContents.send('global-shortcut', 0);

});

globalShortcut.register('ctrl+shift+2', function () {

mainWindow.webContents.send('global-shortcut', 1);

});

});

</pre><p></p><p>首先潭袱,我們需要引入global-shortcut模塊。然后當我們的程序加載完成锋恬,我們注冊兩個快捷鍵--一個響應(yīng)Ctrl屯换,Shift,1組合鍵与学,另一個響應(yīng)Ctrl彤悔,Shift,2組合鍵索守。兩者都會通過「global-shortcut」通道發(fā)送一條帶一個參數(shù)的消息晕窑。我們用這些參數(shù)來播放相應(yīng)的聲音。在index.js中加入以下代碼:</p><pre class="">ipc.on('global-shortcut', function (arg) {

var event = new MouseEvent('click');

soundButtons[arg].dispatchEvent(event);

});

</pre><p>為了方便卵佛,我們會模擬一次按鈕點擊杨赤,用我們創(chuàng)建的soundButton選擇器給按鈕綁定一個播放聲音。當收到帶有參數(shù)1的消息截汪,我們在soundButton[1]元素上模擬一次鼠標點擊(在正式環(huán)境的應(yīng)用疾牲,你應(yīng)該封裝播放聲音的代碼,并執(zhí)行它)衙解。</p>


<h2>在新的窗口修改鍵位配置</h2><pre class="">切換到名為04-global-shortcuts-bound的tag:
git checkout 04-global-shortcuts-bound</pre><p></p><p>系統(tǒng)同時運行很多應(yīng)用程序阳柔,我們預(yù)想的快捷鍵可能已經(jīng)被占用了。這正是我們將要新建一個設(shè)置窗口蚓峦,保存我們想要的鍵位修改的原因舌剂。</p><p>要實現(xiàn)這個目標,我們需要:</p><ul><li>主窗口要有一個設(shè)置按鈕暑椰,</li><li>一個設(shè)置窗口(需要相應(yīng)的HTML霍转,CSS和JavaScript文件),</li><li>ipc消息用來打開干茉,關(guān)閉設(shè)置窗口及更新全局快捷鍵,</li><li>保存或讀取用戶系統(tǒng)里JSON格式的設(shè)置文件很泊。</li></ul><p><b>設(shè)置按鈕和設(shè)置窗口</b></p><p></p><p>類似關(guān)閉主窗口角虫,當點擊設(shè)置按鈕時我們通過通道從index.js發(fā)送消息沾谓。將下面代碼加入index.js:</p><p></p><pre class="">var settingsEl = document.querySelector('.settings');

settingsEl.addEventListener('click', function () {

ipc.send('open-settings-window');

});

</pre><p>點擊設(shè)置按鈕后,通道「open-settings-window」會發(fā)送一條消息到主進程戳鹅。main.js現(xiàn)在需要做出響應(yīng)均驶,新建一個窗口,將下面代碼插入main.js:</p><pre class="">var settingsWindow = null;

ipc.on('open-settings-window', function () {

if (settingsWindow) {

return;

}

settingsWindow = new BrowserWindow({

frame: false,

height: 200,

resizable: false,

width: 200

});

settingsWindow.loadUrl('file://' + __dirname + '/app/settings.html');

settingsWindow.on('closed', function () {

settingsWindow = null;

});

});

</pre><p></p><p>沒有什么新概念枫虏,我們會像打開主窗口一樣打開新的設(shè)置窗口妇穴。不同之處是要先檢查設(shè)置窗口是不是已經(jīng)被打開,以防重復(fù)打開隶债。</p><p>打開后腾它,需要一種方法關(guān)閉設(shè)置窗口。同樣的死讹,我們會通過通道發(fā)送一條消息瞒滴,但這次消息是從settings.js發(fā)出,將下面代碼寫入setting.js:</p><pre class="">'use strict';

var ipc = require('ipc');

var closeEl = document.querySelector('.close');

closeEl.addEventListener('click', function (e) {

ipc.send('close-settings-window');

});

</pre><p></p><p>在main.js里面監(jiān)聽那個通道赞警,代碼如下:</p><pre class="">ipc.on('close-settings-window', function () {

if (settingsWindow) {

settingsWindow.close();

}

});

</pre><p></p><p>我們的設(shè)置窗口就完成了妓忍。</p><p><b>保存和讀取用戶的設(shè)置</b></p><p></p><pre class="">切換到名為05-settings-window-working的tag:
git checkout 05-settings-window-working</pre><p></p><p>與設(shè)置窗口交互,保存設(shè)置愧旦,再讀取到我們的應(yīng)用的過程大致是這樣的:</p><ul><li>編寫一個可以保存和讀取我們在JSON文件中保存設(shè)置信息的辦法世剖,</li><li>初始化設(shè)置窗口時,顯示這些設(shè)置笤虫,</li><li>通過客戶的交互更新設(shè)置旁瘫,</li><li>通知主程序新的設(shè)置。</li></ul><p>我們可以簡單的保存和讀取main.js中的設(shè)置耕皮,但模塊把邏輯抽象出來境蜕,以便我們可以在不同的地方引用,這看看起來更好凌停。</p><p></p><p><b>Working with a JSON configuration</b></p><p>那就是我們新建configuration.js的原因粱年。Node.js用<a target="_blank">CommonJS模塊規(guī)范</a>,這意味著你只可以暴露你的API罚拟,而其他文件或方法會引用API提供的方法台诗。</p><p>

</p><p>為了讓保存和讀取更簡便,使用nconf模塊赐俗,它已經(jīng)為我們抽象出讀取和寫入JSON文件的方法拉队,非常符合我們的需求。但首先阻逮,我們要在CLI中執(zhí)行下面的命令將它引入項目中:
</p><pre class="">npm install --save nconf</pre><p></p><p>npm將nconf模塊作為應(yīng)用的依賴安裝粱快。在我們打包應(yīng)用給終端用戶時(相對用save-dev參數(shù)會只在開發(fā)環(huán)境中引入模塊)將被引入和使用。</p><p>configuration.js文件非常的簡單,在項目根目錄下新建configuration.js文件事哭,寫入代碼:</p><pre class="">'use strict';

var nconf = require('nconf').file({file: getUserHome() + '/sound-machine-config.json'});

function saveSettings(settingKey, settingValue) {

nconf.set(settingKey, settingValue);

nconf.save();

}

function readSettings(settingKey) {

nconf.load();

return nconf.get(settingKey);

}

function getUserHome() {

return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];

}

module.exports = {

saveSettings: saveSettings,

readSettings: readSettings

};

</pre><p></p><p></p><p>nconf只需要知道你的設(shè)置要保存到哪里漫雷,這里我們設(shè)置為客戶的主文件夾和一個文件名。獲取用戶的主文件夾非常簡單鳍咱,只需要區(qū)別不同系統(tǒng)調(diào)用Node.js(process.env)(如用getUserHome()方法)降盹。</p><p>通過nconf的內(nèi)建方法來保存或讀取設(shè)置(set()方法保存,get()方法讀取谤辜,用save()和load()方法進行文件操作)蓄坏,用符合CommonJS規(guī)范的module.exports語法來導(dǎo)出API。</p><p><b>初始化修改的快捷鍵</b></p><p></p><p>在我們進行設(shè)置的交互之前丑念,應(yīng)初始化設(shè)置涡戳,以防我們先啟動應(yīng)用丟失設(shè)置信息。我們把變更鍵保存在一個數(shù)組中渠欺,數(shù)組以「shortcutKeys」為鍵妹蔽,在main.js里初始化,我們首先要引用configuration模塊:</p><pre class="">'use strict';

var configuration = require('./configuration');

app.on('ready', function () {

if (!configuration.readSettings('shortcutKeys')) {

configuration.saveSettings('shortcutKeys', ['ctrl', 'shift']);

}

...

}

</pre><p></p><p>嘗試讀取「shortcutKeys」鍵對應(yīng)的值挠将,如果讀取不到胳岂,就設(shè)置一個初始值。</p><p>現(xiàn)在要重寫main.js中的全局快捷鍵舔稀,這個方法可以在后面更新設(shè)置的時候直接調(diào)用乳丰。 去掉原來在main.js中注冊快捷鍵的方法,改成:</p><pre class="">app.on('ready', function () {

...

setGlobalShortcuts();

}

function setGlobalShortcuts() {

globalShortcut.unregisterAll();

var shortcutKeysSetting = configuration.readSettings('shortcutKeys');

var shortcutPrefix = shortcutKeysSetting.length === 0 ? '' : shortcutKeysSetting.join('+') + '+';

globalShortcut.register(shortcutPrefix + '1', function () {

mainWindow.webContents.send('global-shortcut', 0);

});

globalShortcut.register(shortcutPrefix + '2', function () {

mainWindow.webContents.send('global-shortcut', 1);

});

}

</pre><p></p><p>方法會重置全局快捷鍵内贮,現(xiàn)在我們可以設(shè)置新的快捷鍵产园,從設(shè)置文件讀取變更鍵數(shù)組,轉(zhuǎn)換<a target="_blank">類加速器規(guī)則字符串</a>夜郁,再注冊全局快捷鍵什燕。</p><p><b>與設(shè)置窗口交互</b></p><p>回到settings.js,我們要綁定click事件來修改我們的全局快捷鍵竞端。首先屎即,我們遍歷所有勾選的復(fù)選框(從configuration模塊中讀取):</p><pre class="">var configuration = require('../configuration.js');

var modifierCheckboxes = document.querySelectorAll('.global-shortcut');

for (var i = 0; i < modifierCheckboxes.length; i++) {

var shortcutKeys = configuration.readSettings('shortcutKeys');

var modifierKey = modifierCheckboxes[i].attributes['data-modifier-key'].value;

modifierCheckboxes[i].checked = shortcutKeys.indexOf(modifierKey) !== -1;

... // Binding of clicks comes here

}

</pre><p></p><p>現(xiàn)在我們要給復(fù)選框綁定行為事富。記得設(shè)置窗口(渲染進程)不能改動GUI綁定技俐。這意味著我們需要從setting.js通過ipc發(fā)送消息(后面會處理消息):</p><pre class="">for (var i = 0; i < modifierCheckboxes.length; i++) {

...

modifierCheckboxes[i].addEventListener('click', function (e) {

bindModifierCheckboxes(e);

});

}

function bindModifierCheckboxes(e) {

var shortcutKeys = configuration.readSettings('shortcutKeys');

var modifierKey = e.target.attributes['data-modifier-key'].value;

if (shortcutKeys.indexOf(modifierKey) !== -1) {

var shortcutKeyIndex = shortcutKeys.indexOf(modifierKey);

shortcutKeys.splice(shortcutKeyIndex, 1);

}

else {

shortcutKeys.push(modifierKey);

}

configuration.saveSettings('shortcutKeys', shortcutKeys);

ipc.send('set-global-shortcuts');

}

</pre><p></p><p>我們遍歷了所有的復(fù)選框,綁定click事件统台,在每次點擊時判斷是否含有變更鍵雕擂。然后根據(jù)結(jié)果,修改數(shù)組贱勃,保存結(jié)果到設(shè)置井赌,再給主進程發(fā)送消息谤逼,它會更新我們的全局快捷鍵。</p><p>下面要在main.js里的設(shè)置「set-global-shortcuts」這個ipc通道來更新我們的全局快捷鍵:</p><pre class="">ipc.on('set-global-shortcuts', function () {

setGlobalShortcuts();

});

</pre><p></p><p></p><p>很簡單仇穗,像這樣森缠,我們的全局快捷鍵就配置好了!</p>


<h2>菜單上有什么?</h2><pre class="">切換到名為06-shortcuts-configurable的tag:
git checkout 06-shortcuts-configurable</pre><p>對桌面應(yīng)用來說,另一個重要的概念就是菜單欄仪缸。分為上下文菜單(右擊菜單),托盤菜單(綁定到托盤圖標)列肢,應(yīng)用菜單(在OS X上)等多種恰画。</p><p>
</p><p>在本指南中,我們將添加一個綁定菜單的托盤圖標瓷马。我們也會利用這次機會探索另一種進程間通信--<a target="_blank">remote模塊</a>拴还。
</p><p>remote模塊實現(xiàn)從渲染進程向主進程發(fā)送RPC式調(diào)用。你引入模塊欧聘,在渲染進程操作片林,方法在主進程被初始化,你調(diào)用的方法都在主進程被執(zhí)行怀骤。實際中费封,這意味著你在index.js遠程請求原生的GUI模塊,調(diào)用它們的方法蒋伦,都會在main.js中執(zhí)行弓摘。你可以在index.js里引入BrowserWindow模塊,初始化一個瀏覽器窗口痕届。背后的原理是韧献,異步調(diào)用新的瀏覽器窗口的主進程。</p><p>
</p><p>
</p><p>現(xiàn)在我們創(chuàng)建一個菜單研叫,并把它綁定到托盤圖標锤窑,在index.js中加入下面代碼:</p><pre class="">var remote = require('remote');

var Tray = remote.require('tray');

var Menu = remote.require('menu');

var path = require('path');

var trayIcon = null;

if (process.platform === 'darwin') {

trayIcon = new Tray(path.join(__dirname, 'img/tray-iconTemplate.png'));

}

else {

trayIcon = new Tray(path.join(__dirname, 'img/tray-icon-alt.png'));

}

var trayMenuTemplate = [

{

label: 'Sound machine',

enabled: false

},

{

label: 'Settings',

click: function () {

ipc.send('open-settings-window');

}

},

{

label: 'Quit',

click: function () {

ipc.send('close-main-window');

}

}

];

var trayMenu = Menu.buildFromTemplate(trayMenuTemplate);

trayIcon.setContextMenu(trayMenu);

</pre><p></p><p>原生的GUI模塊(菜單和托盤)的方法會被遠程調(diào)用,是很安全的嚷炉。</p><p>把圖標定義成托盤圖標渊啰。OS X支持圖像模板(依照慣例,圖像的文件名以「Template」結(jié)尾渤昌,可以被當做一個模板圖像)虽抄,這讓使用深淺色主題變得很容易。其他系統(tǒng)用常規(guī)的圖標独柑。</p><p>在Electron中有很多種方法創(chuàng)建菜單迈窟。我們的方法是創(chuàng)建一個菜單模板(一個包含菜單項的簡單數(shù)組),用那個模板創(chuàng)建菜單忌栅。最后车酣,綁定新的菜單到托盤圖標曲稼。</p><p></p>


<h2>打包你的應(yīng)用</h2><pre class="">切換到名為07-ready-for-packaging的tag:
git checkout 07-ready-for-packaging</pre><p></p><p>如果不能讓人們下載使用,這樣的應(yīng)用有什么意義湖员?</p><p>
</p><p>
</p><p></p><p>用「<a target="_blank">electron-packager</a>」為所有系統(tǒng)打包你的應(yīng)用很簡單贫悄。簡單來說,「electron-packager」幫你完成所有用Electron打包你應(yīng)用的工作娘摔,最終生成你要發(fā)布的平臺的安裝包窄坦。</p><p>它可以作為CLI應(yīng)用或構(gòu)建過程的一部分,更復(fù)雜的構(gòu)建情況不在本文所涉及范圍內(nèi)凳寺,但我們?nèi)绻苡么虬_本鸭津,會使打包更簡單。用「electron-packager」比較麻煩肠缨,打包應(yīng)用的基本命令是:</p><p></p><pre class="">electron-packager <location of project> <name of project> <platform> <architecture> <electron version> <optional options></pre><p></p><p>其中逆趋,</p><ul><li>location of project是你項目文件夾的位置,</li><li>name of project定義你的項目名晒奕,</li><li>platform決定要構(gòu)建的平臺(all 包括Windows闻书,Mac和Linux ),</li><li>architecture決定構(gòu)建哪個構(gòu)架下(x86或x64脑慧,all表示兩者)魄眉,</li><li>electron version讓你選擇要用的Electron版本</li></ul><p></p><p>第一次打包用時比較久,因為要下載平臺的二進制文件闷袒,隨后的打包將會快的多杆融。</p><p>我(在Mac系統(tǒng))打包發(fā)聲器應(yīng)用的命令是:</p><p></p><pre class="">electron-packager ~/Projects/sound-machine SoundMachine --all --version=0.30.2 --out=~/Desktop --overwrite --icon=~/Projects/sound-machine/app/img/app-icon.icns</pre><p></p><p>命令的選項理解起來都比較簡單。為了獲得精美的圖標霜运,你首先要找一款類似<a target="_blank">這個軟件</a>可以把PNG文件轉(zhuǎn)換到這些格式的工具脾歇,把它轉(zhuǎn)換成.icns格式(Mac用)或者.ico格式(Window用)。如果在非Windows系統(tǒng)給Windows平臺的應(yīng)用打包淘捡,你需要安裝wine(Mac用戶用brew藕各,Linux用戶用apt-get)。</p><p>每次都打這么長的命令很不方便焦除,可以在package.json中加另一個腳本激况。首先,把electron-packager作為開發(fā)依賴安裝:</p><p></p><pre class="">npm install --save-dev electron-packager</pre><p>現(xiàn)在我們可以在package.json中添加腳本:</p><pre class="">"scripts": {

"start": "electron .",

"package": "electron-packager ./ SoundMachine --all --out ~/Desktop/SoundMachine --version 0.30.2 --overwrite --icon=./app/img/app-icon.icns"

}</pre><p>在命令行里執(zhí)行下面的命令:</p><pre class="">npm run-script package</pre><p></p><p>這個打包命令會啟動electron-packager膘魄,在當前目錄下找到目標應(yīng)用文件乌逐,打包,保存到桌面创葡。如果你用的是Windows系統(tǒng)浙踢,需要修改腳本,不過改動很小灿渴。</p><p>當前狀態(tài)的發(fā)聲器洛波,最后打包后大小高達100MB胰舆。別擔心,可以把它壓縮到不到一半的容量蹬挤。</p><p>如果你想要更進一步缚窿,可以嘗試<a target="_blank">electron-builder</a>,它用electron-packager生成的打包好的文件焰扳,可以生成自動安裝包倦零。</p><p></p>


<h2>可以添加的其他功能</h2><p></p><p>應(yīng)用已經(jīng)打包好,準備就緒吨悍。你也可以添加自己想要的功能光绕。</p><p>這是一些想法:</p><ul><li>可以顯示應(yīng)用的快捷鍵,作者等信息的幫助界面畜份,</li><li>加一個綁定菜單的圖標入口可以打開信息界面,</li><li>為了更快的編譯和分發(fā)欣尼,編寫打包的腳本爆雹,</li><li>用<a target="_blank">node-notifier</a>加入通知功能,推送用戶正播放的是什么聲音愕鼓,</li><li>用lodash得到更整潔的代碼钙态,</li><li>打包應(yīng)用前,將你所有的CSS和JavaScript文件用構(gòu)建工具壓縮菇晃,</li><li>檢查應(yīng)用是否有新版本册倒,用服務(wù)器調(diào)用之前介紹的node-notifier并通知客戶</li></ul><p>挑戰(zhàn)來了--嘗試抽取出發(fā)聲器瀏覽器窗口的邏輯,用這些邏輯在瀏覽器中創(chuàng)建web頁面磺送,實現(xiàn)相同的發(fā)聲器驻子。一個代碼庫--兩個產(chǎn)品(桌面應(yīng)用和web應(yīng)用),超棒估灿!</p><p></p>
<p></p><h1>深入Electron</h1><p>我們只接觸到了Electron比較淺顯知識崇呵。實際上,實現(xiàn)如查看主機電源選項或在界面上顯示多種信息都很簡單馅袁。這些功能已經(jīng)內(nèi)建好域慷,請<a target="_blank">查閱Electronde API文檔</a>。</p><p>Electron的API文檔只是Electron在Github上資料庫的一小部分汗销,其他文件夾也值得一看犹褒。</p><p>Sindre Sorhus正在維護<a target="_blank">超酷的Electron資源列表</a>,你可以在列表中找到很多很酷的項目弛针,也有Electron應(yīng)用構(gòu)架方面很好的總結(jié)叠骑,可以學(xué)習(xí)之后重構(gòu)我們的代碼。</p><p>最后削茁,Electron是基于io.js(將合并回Node.js)的座云,兼容絕大部分的Node.js模塊疙赠,可以用來擴展你的應(yīng)用,查看<a target="_blank">npmjs.com</a>來獲取你需要的信息朦拖。</p>
<p></p><h1>這就完了圃阳?</h1><p>當然不是。</p><p>現(xiàn)在是時候來創(chuàng)建更復(fù)雜的應(yīng)用了璧帝。在本指南中捍岳,我沒有選擇用更多函數(shù)庫和構(gòu)建工具,只強調(diào)了重要的概念睬隶。你也可以用ES6或Typescript來寫你的應(yīng)用锣夹,使用Angular或React框架,用gulp或Grunt來簡化你的構(gòu)建過程苏潜。</p><p>為什么不用你最喜歡的語言银萍,框架和構(gòu)建工具,配合Flickr API恤左,node-flickrapi創(chuàng)建一個Flickr桌面同步應(yīng)用呢贴唇?或者用Google官方的Node.js函數(shù)庫創(chuàng)建一個Gmail客戶端?</p><p>選一個吸引你的想法飞袋,創(chuàng)建一個資料庫戳气,開始做吧。</p></div>

<div class="bbox">

本文來自<a target="_blank">GET社區(qū)翻譯計劃</a>巧鸭,每翻譯一篇高質(zhì)量文章瓶您,可獲100元獎金。翻譯計劃贊助商:

<ul class="binfo">

<li><a target="_blank">

</a></li>

</ul>

轉(zhuǎn)載必須保留來源和以上贊助商信息纲仍。

</div>

<div class="sinfo exp">

本文由 <a href="/1.user" target="_blank">Easy<span aria-hidden="true" class="jdc-jobdeer jdcicon"></span></a> 第一時間收藏到

GET呀袱,原文來自 → <a target="_blank"> medium.com </a>

</div>

<ul class="get-article-actions">

<li><a target="_blank">分享到微博</a></li>

<li class="kblink-7870"><a href="javascript:add2kb('7870','top');" >收藏本文</a></li>

<li class="followlink-1"><a href="javascript:follow('1');void(0);">關(guān)注@Easy</a></li>

</ul>

<div class="visible-xs-block wxlast">

<center>

<p>「GetParty」</p>

<p>關(guān)注微信號,推送好文章</p>

<p>微信中長按圖片即可關(guān)注</p>

<p><a href="/?fr=qrbt" class="btn btn-success">更多精選文章</a></p>

</center>

</div>

<div id="article-7870">

<a href="javascript:toggle_inline_comment('7870','article');void(0);" class="get" name="comment"><span class="jdc-coffee"></span>評論(4)</a>

<div class="top20"></div>

</div>

<script>toggle_inline_comment('7870','article');

$(".timeago").timeago();</script>

<div class="hbox"></div>

</div>

<script>

$( document ).ready(function() {

highlight();

// 支持圖片分享到微博

setTimeout( function()

{

$('.get-article-area').imgShare();

} , 2000 );

});

</script>

</div>

<div class="hidden-xs col-sm-3 sidebar-offcanvas" id="sidebar" role="navigation">

<input class="nh" type="checkbox" onchange="change2('https://medium.com/@bojzi/building-a-desktop-application-with-electron-204203eeb658');$(this).prop('checked', false);" />

<script type="text/javascript">

$('input.nh').onoff();

</script>

<script>

$('.sinfo.exp').waypoint(function(direction) {

if( direction == 'down' )

{

$("#wechat_code").show();

}

if( direction == 'up' )

{

$("#wechat_code").hide();

}

},{ offset:'bottom-in-view'});

</script>

<div id="wechat_code">

<p>關(guān)注微信號郑叠,推送好文章</p>

</div> </div>

</div>

<div class="get-last"></div>

<div class="get-user-menu">

<a href="/?c=weibo&a=login" class="link">微博一鍵登入</a><span class="top" ><a href="#"><span class="jdc-arrow-up-thick"></span></a></span>

</div>

<div class="modal fade" id="get_float" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" >

<div class="modal-dialog">

</div>

</div>

<div id="get_aside" class="clearfix">

<div class="pull-right"><a href="javascript:hide_aside();void(0);" class="get btn">×</a></div>

<div class="content"><center class="top50">

</center></div>

</div>

<div id="shadow_dom"></div>

<script type="text/javascript">

//emojify.run();

//$('#get_float').modal();

$(window).scroll( function()

{

var value = $(document).scrollTop();

//console.log('in value='+value);

if ( value > 0 )

$("#theheader").addClass('smaller');

else

$("#theheader").removeClass('smaller');

});

if( $(".snapbox").length > 0 )

$(".snapbox").append($("<div class='floatingfooter'></div>"));

$( document ).ready(function() {

$( '.yue a[href^="http://"]' ).attr( 'target','_blank' );

$( '.yue a[href^="https://"]' ).attr( 'target','_blank' );

});

</script>

</div>

</body>

</html>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末压鉴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锻拘,更是在濱河造成了極大的恐慌油吭,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件署拟,死亡現(xiàn)場離奇詭異婉宰,居然都是意外死亡,警方通過查閱死者的電腦和手機推穷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門心包,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人馒铃,你說我怎么就攤上這事蟹腾『弁铮” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵娃殖,是天一觀的道長值戳。 經(jīng)常有香客問我,道長炉爆,這世上最難降的妖魔是什么堕虹? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮芬首,結(jié)果婚禮上赴捞,老公的妹妹穿的比我還像新娘。我一直安慰自己郁稍,他們只是感情好赦政,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耀怜,像睡著了一般恢着。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上封寞,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音仅财,去河邊找鬼狈究。 笑死,一個胖子當著我的面吹牛盏求,可吹牛的內(nèi)容都是我干的抖锥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼碎罚,長吁一口氣:“原來是場噩夢啊……” “哼磅废!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荆烈,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拯勉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后憔购,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宫峦,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年玫鸟,在試婚紗的時候發(fā)現(xiàn)自己被綠了导绷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡屎飘,死狀恐怖妥曲,靈堂內(nèi)的尸體忽然破棺而出贾费,到底是詐尸還是另有隱情,我是刑警寧澤檐盟,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布褂萧,位于F島的核電站,受9級特大地震影響遵堵,放射性物質(zhì)發(fā)生泄漏箱玷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一陌宿、第九天 我趴在偏房一處隱蔽的房頂上張望锡足。 院中可真熱鬧,春花似錦壳坪、人聲如沸舶得。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堵未。三九已至,卻和暖如春嫉你,著一層夾襖步出監(jiān)牢的瞬間名段,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工发框, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躺彬,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓梅惯,卻偏偏與公主長得像宪拥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铣减,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容