V začetku tega leta je Github izdal Atom-Shell, jedro svojega slavnega odprtokodnega urejevalnika Atom in ga preimenoval v Electron za posebno priložnost.
Electron v nasprotju z drugimi konkurenti v kategoriji namiznih aplikacij, ki temeljijo na Node.js, s svojim združevanjem moči Node.js prinaša svoj zasuk na ta že uveljavljeni trg ( io.js do nedavnih izdaj) z Kromov motor da nam prinese najboljše tako strežniški kot odjemalski JavaScript.
Predstavljajte si svet, v katerem bi lahko ustvarili zmogljive namizne aplikacije na več platformah, ki temeljijo na podatkih, ki jih poganja ne samo vedno večje skladišče modulov NPM, temveč tudi celoten register Bower, da izpolnimo vse potrebe strank.
Enter Electron .
V tej vadnici bomo z uporabo programov Electron, Angular.js in Loki.js , lahka baza podatkov v pomnilniku z znano sintakso za Razvijalci MongoDB .
Na voljo je celotna izvorna koda za to aplikacijo tukaj .
Ta vadnica predpostavlja, da:
Najprej moramo dobiti binarne datoteke Electron, da bomo lahko lokalno preizkusili našo aplikacijo. Lahko ga namestimo globalno in ga uporabimo kot CLI ali pa ga namestimo lokalno na poti naše aplikacije. Priporočam, da ga namestite globalno, tako da nam tega ni treba znova in znova izvajati za vsako aplikacijo, ki jo razvijemo.
Kasneje se bomo naučili, kako pakirati našo aplikacijo za distribucijo z Gulpom. Ta postopek vključuje kopiranje binarnih datotek Electron, zato je malo ali brez smisla, da ga ročno namestite na pot naše aplikacije.
Če želite namestiti Electron CLI, lahko v naš terminal vnesemo naslednji ukaz:
$ npm install -g electron-prebuilt
Če želite preizkusiti namestitev, vnesite electron -h
in mora prikazati različico Electron CLI.
V času pisanja tega članka je bila različica Electron 0.31.2
.
Predpostavimo naslednjo osnovno strukturo map:
my-app |- cache/ |- dist/ |- src/ |-- app.js | gulpfile.js
… kje: - predpomnilnik/ bo uporabljen za prenos brskalnikov Electron pri izdelavi aplikacije. - dist / bo vseboval ustvarjene distribucijske datoteke. - src / bo vseboval našo izvorno kodo. - src / app.js bo vstopna točka naše prijave.
Nato se bomo pomaknili do src/
v našem terminalu in ustvarite package.json
in bower.json
datoteke za našo aplikacijo:
$ npm init $ bower init
Potrebne pakete bomo namestili kasneje v tej vadnici.
Electron razlikuje med dvema vrstama procesov:
Zaradi jasnosti kode je treba za vsak postopek upodabljanja uporabiti ločeno datoteko. Če želite določiti glavni postopek za našo aplikacijo, bomo odprli
src/app.js
in vključujejoapp
modul za zagon aplikacije inbrowser-window
modul za ustvarjanje različnih oken naše aplikacije (oba dela jedra Electron), kot takih:
var app = require('app'), BrowserWindow = require('browser-window');
Ko se aplikacija dejansko zažene, sproži ready
dogodek, na katerega se lahko vežemo. Na tem mestu lahko ustvarimo glavno okno naše aplikacije:
var mainWindow = null; app.on('ready', function() { mainWindow = new BrowserWindow({ width: 1024, height: 768 }); mainWindow.loadUrl('file://' + __dirname + '/windows/main/main.html'); mainWindow.openDevTools(); });
Ključne točke:
BrowserWindow
predmet.loadUrl()
metoda, ki nam omogoča, da v trenutno okno naložimo vsebino dejanske datoteke HTML. Datoteka HTML je lahko lokalno ali na daljavo .openDevTools()
metoda, ki nam omogoča, da v trenutnem oknu za namene odpravljanja napak odpremo primerek Chrome Dev Tools.Nato bi morali malo organizirati našo kodo. Priporočam, da ustvarite windows/
mapa v naši src/
in kjer lahko za vsako okno ustvarimo podmapo kot tako:
my-app |- src/ |-- windows/ |--- main/ |---- main.controller.js |---- main.html |---- main.view.js
… Kjer main.controller.js
bo vseboval logiko naše strani na strani strežnika in main.view.js
bo vseboval logiko naše stranke na strani odjemalca.
The main.html
datoteka je preprosto spletna stran HTML5, zato jo lahko preprosto zaženemo tako:
Password Keychain
Na tej točki mora biti naša aplikacija pripravljena za zagon. Če ga želite preizkusiti, lahko preprosto vtipkamo v naš terminal, v koren | | + + _ | mapa:
src
Ta postopek lahko avtomatiziramo z določitvijo
$ electron .
skript datoteke package.son.
Za izdelavo aplikacije za zaklepanje gesel potrebujemo: - Način za dodajanje, ustvarjanje in shranjevanje gesel. - Priročen način kopiranja in odstranjevanja gesel.
Za vstavljanje novih gesel zadostuje preprost obrazec. Za predstavitev komunikacije med več okni v Electronu začnite z dodajanjem drugega okna v našo aplikacijo, ki bo prikazalo obrazec »vstavi«. Ker bomo to okno večkrat odprli in zaprli, bi morali logiko zaviti v metodo, tako da jo lahko preprosto pokličemo, kadar je to potrebno:
start
Ključne točke:
Ideja je, da lahko sproži okno 'vstavi', ko končni uporabnik klikne gumb v 'glavnem' oknu. Da bi to naredili, bomo morali iz glavnega okna v glavni postopek poslati sporočilo z navodili, naj odpre okno za vstavljanje. To lahko dosežemo z uporabo elektronskega IPC modula. Dejansko obstajata dve različici modula IPC:
Čeprav je Electronov komunikacijski kanal večinoma enosmeren, je do IPC modula glavnega procesa mogoče v postopku upodabljanja z uporabo na daljavo modul. Glavni postopek lahko pošlje sporočilo nazaj v postopek upodabljanja, iz katerega je dogodek izviral, z uporabo Event.sender.send () metoda.
Za uporabo modula IPC potrebujemo le njega kot kateri koli drug modul NPM v našem skriptu glavnega procesa:
function createInsertWindow() { insertWindow = new BrowserWindow({ width: 640, height: 480, show: false }); insertWindow.loadUrl('file://' + __dirname + '/windows/insert/insert.html'); insertWindow.on('closed',function() { insertWindow = null; }); }
… In se nato veže na dogodke z var ipc = require('ipc');
metoda:
on()
Ključne točke:
ipc.on('toggle-insert-view', function() { if(!insertWindow) { createInsertWindow(); } return (!insertWindow.isClosed() && insertWindow.isVisible()) ? insertWindow.hide() : insertWindow.show(); });
država.Zdaj moramo dejansko sprožiti ta dogodek iz postopka upodabljanja. Ustvarili bomo novo datoteko skripta z imenom closed
in jo dodali na našo stran HTML, kot bi to storili s katerim koli običajnim skriptom:
main.view.js
Nalaganje datoteke skripta prek HTML-ja
script
tag naloži to datoteko v kontekstu na strani odjemalca. To pomeni, da so na primer globalne spremenljivke na voljo prekwindow.
. Če želite skript naložiti v kontekst na strani strežnika, lahko uporabimorequire()
metoda neposredno na naši strani HTML:require('./main.controller.js');
.
Čeprav je skript naložen v na strani stranke V kontekstu lahko še vedno dostopamo do modula IPC za postopek upodabljanja na enak način kot za glavni postopek in nato pošljemo svoj dogodek kot tak:
var ipc = require('ipc'); angular .module('Utils', []) .directive('toggleInsertView', function() { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); ipc.send('toggle-insert-view'); }); }; });
Na voljo je tudi metoda sendSync (), če moramo svoje dogodke pošiljati sinhrono.
Zdaj nam preostane le še, da odpremo okno »vstavi«, da ustvarimo gumb HTML z ustreznimi direktivami Angular:
add
In to direktivo dodajte kot odvisnost kotnega krmilnika glavnega okna:
angular .module('MainWindow', ['Utils']) .controller('MainCtrl', function() { var vm = this; });
Če želimo stvari poenostaviti, lahko preprosto uporabimo NPM uuid
modul za generiranje enoličnih ID-jev, ki bodo v tej vadnici delovali kot gesla. Lahko ga namestimo kot kateri koli drug modul NPM, zahtevamo ga v našem skriptu ‘Utils’ in nato ustvarimo preprosto tovarno, ki bo vrnila edinstven ID:
var uuid = require('uuid'); angular .module('Utils', []) ... .factory('Generator', function() { return { create: function() { return uuid.v4(); } }; })
Zdaj nam preostane le še, da v pogledu za vstavljanje ustvarimo gumb in mu priložimo direktivo, ki bo poslušala dogodke klika na gumbu in poklicala metodo create ():
generate
// in Utils.js angular .module('Utils', []) ... .directive('generatePassword', ['Generator', function(Generator) { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); if(!scope.vm.formData) scope.vm.formData = {}; scope.vm.formData.password = Generator.create(); scope.$apply(); }); }; }])
Na tej točki želimo shraniti svoja gesla. Struktura podatkov za vnose z gesli je dokaj preprosta:
{ 'id': String 'description': String, 'username': String, 'password': String }
Torej vse, kar v resnici potrebujemo, je nekakšna baza podatkov v pomnilniku, ki se lahko poljubno sinhronizira z datoteko za varnostno kopiranje. V ta namen se zdi Loki.js idealen kandidat. Naredi točno tisto, kar potrebujemo za namen te aplikacije, poleg tega pa ponuja še Dinamični pogledi funkcija, ki nam omogoča, da počnemo stvari, podobne agregatnemu modulu MongoDB.
Dynamic Views ne ponujajo vseh funkcij, ki jih ponuja agregatni modul MongodDB. Glejte dokumentacijo za več informacij.
Začnimo z ustvarjanjem preprostega obrazca HTML:
Description... Username... Password... generate cancel save
Zdaj pa dodajte logiko JavaScript za obdelavo objav in shranjevanje vsebine obrazca:
var loki = require('lokijs'), path = require('path'); angular .module('Utils', []) ... .service('Storage', ['$q', function($q) { this.db = new loki(path.resolve(__dirname, '../..', 'app.db')); this.collection = null; this.loaded = false; this.init = function() { var d = $q.defer(); this.reload() .then(function() { this.collection = this.db.getCollection('keychain'); d.resolve(this); }.bind(this)) .catch(function(e) { // create collection this.db.addCollection('keychain'); // save and create file this.db.saveDatabase(); this.collection = this.db.getCollection('keychain'); d.resolve(this); }.bind(this)); return d.promise; }; this.addDoc = function(data) { var d = $q.defer(); if(this.isLoaded() && this.getCollection()) { this.getCollection().insert(data); this.db.saveDatabase(); d.resolve(this.getCollection()); } else { d.reject(new Error('DB NOT READY')); } return d.promise; }; }) .directive('savePassword', ['Storage', function(Storage) { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); if(scope.vm.formData) { Storage .addDoc(scope.vm.formData) .then(function() { // reset form & close insert window scope.vm.formData = {}; ipc.send('toggle-insert-view'); }); } }); }; }])
Ključne točke:
getCollection()
metoda.insert()
metoda, ki nam omogoča, da v zbirko dodamo nov dokument.saveDatabase()
metoda.Zdaj imamo preprost obrazec, ki nam omogoča ustvarjanje in shranjevanje novih gesel. Vrnimo se v glavni pogled, da naštejemo te vnose.
Tu se mora zgoditi nekaj stvari:
Seznam dokumentov lahko poiščemo tako, da pokličete getCollection()
metoda na objektu Loki. Ta metoda vrne objekt z lastnostjo imenovano podatkov , ki je preprosto niz vseh dokumentov v tej zbirki:
this.getCollection = function() { this.collection = this.db.getCollection('keychain'); return this.collection; }; this.getDocs = function() { return (this.getCollection()) ? this.getCollection().data : null; };
Nato lahko pokličemo getDocs () v našem kotnem krmilniku in pridobimo vsa gesla, shranjena v zbirki podatkov, potem ko jo inicializiramo:
angular .module('MainView', ['Utils']) .controller('MainCtrl', ['Storage', function(Storage) { var vm = this; vm.keychain = null; Storage .init() .then(function(db) { vm.keychain = db.getDocs(); }); });
Nekaj kotne predloge in imamo seznam gesel:
{{item.description}} {item.username } • copy remove
Lepa dodana funkcija bi bila osvežitev seznama gesel po vstavitvi novega. Za to lahko uporabimo Electronov IPC modul. Kot smo že omenili, lahko modul IPC glavnega procesa pokličete v postopku upodabljalnika, da ga z oddaljenim modulom spremenite v postopek poslušalca. Tu je primer, kako ga uporabiti v main.view.js
var remote = require('remote'), remoteIpc = remote.require('ipc'); angular .module('MainView', ['Utils']) .controller('MainCtrl', ['Storage', function(Storage) { var vm = this; vm.keychain = null; Storage .init() .then(function(db) { vm.keychain = db.getDocs(); remoteIpc.on('update-main-view', function() { Storage .reload() .then(function() { vm.keychain = db.getDocs(); }); }); }); }]);
Ključne točke:
require()
metoda, ki od glavnega procesa zahteva oddaljeni modul IPC.on()
metode in na te dogodke povežite funkcije povratnega klica.Pogled vstavitve bo nato zadolžen za pošiljanje tega dogodka, kadar bo shranjen nov dokument:
Storage .addDoc(scope.vm.formData) .then(function() { // refresh list in main view ipc.send('update-main-view'); // reset form & close insert window scope.vm.formData = {}; ipc.send('toggle-insert-view'); });
Običajno ni dobro, da gesla prikazujete v navadnem besedilu. Namesto tega bomo skrili in zagotovili priročen gumb, ki bo končnemu uporabniku omogočil neposredno kopiranje gesla za določen vnos.
Tudi tu nas Electron reši tako, da nam priskrbi a odložišče modul z enostavnimi metodami za kopiranje in lepljenje ne samo besedilne vsebine, temveč tudi slik in kode HTML:
var clipboard = require('clipboard'); angular .module('Utils', []) ... .directive('copyPassword', [function() { return function(scope, el, attrs) { el.bind('click', function(e) { e.preventDefault(); var text = (scope.vm.keychain[attrs.copyPassword]) ? scope.vm.keychain[attrs.copyPassword].password : ''; // atom's clipboard module clipboard.clear(); clipboard.writeText(text); }); }; }]);
Ker bo ustvarjeno geslo preprost niz, lahko uporabimo writeText()
za kopiranje gesla v sistemsko odložišče. Nato lahko posodobimo svoj glavni pogled HTML in dodamo gumb za kopiranje z copy-password
direktivo, ki vsebuje indeks nabora gesel:
copy
Naši končni uporabniki bi morda želeli tudi izbrisati gesla, če bi zastarala. Da bi to naredili, moramo le poklicati remove()
na zbirki obeskov za ključe. Celoten dokument moramo posredovati metodi ‘remove ()’, kot taki:
this.removeDoc = function(doc) { return function() { var d = $q.defer(); if(this.isLoaded() && this.getCollection()) { // remove the doc from the collection & persist changes this.getCollection().remove(doc); this.db.saveDatabase(); // inform the insert view that the db content has changed ipc.send('reload-insert-view'); d.resolve(true); } else { d.reject(new Error('DB NOT READY')); } return d.promise; }.bind(this); };
V dokumentaciji Loki.js je zapisano, da lahko dokument odstranimo tudi z njegovim id, vendar se zdi, da ne deluje po pričakovanjih.
Electron se brez težav integrira z našim namiznim okoljem OS, da našim aplikacijam nudi videz in občutek uporabniške izkušnje. Zato je Electron v kompletu z a Menijski modul , namenjen ustvarjanju zapletenih struktur menijev namizja za našo aplikacijo.
Menijski modul je obsežna tema in si skoraj zasluži lastno vadnico. Toplo priporočam, da preberete Electronova vadnica za integracijo namiznega okolja odkriti vse značilnosti tega modula.
Za obseg te trenutne vadnice bomo videli, kako ustvariti meni po meri, mu dodati ukaz po meri in implementirati standardni ukaz quit.
Običajno bi logika JavaScript za meni Electron pripadala glavni datoteki skripta naše aplikacije, kjer je definiran naš glavni postopek. Lahko pa ga povzamemo v ločeno datoteko in do oddaljenega modula dostopamo do modula Menu:
var remote = require('remote'), Menu = remote.require('menu');
Za določitev preprostega menija bomo morali uporabiti buildFromTemplate()
metoda:
var appMenu = Menu.buildFromTemplate([ { label: 'Electron', submenu: [{ label: 'Credits', click: function() { alert('Built with Electron & Loki.js.'); } }] } ]);
Prvi element v matriki se vedno uporablja kot 'privzeti' element menija.
Vrednost
label
lastnost za privzeti element menija ni veliko pomembna. V načinu za razvijalce bo vedno prikazalElectron
. Kasneje bomo videli, kako v fazi gradnje privzetemu elementu menija dodelite ime po meri.
Nazadnje moramo ta meni po meri dodeliti kot privzeti meni za našo aplikacijo z setApplicationMenu()
metoda:
Menu.setApplicationMenu(appMenu);
Electron zagotavlja pospeševalniki ”, Niz vnaprej določenih nizov, ki se preslikajo na dejanske kombinacije tipkovnice, npr .: Command+A
ali Ctrl+Shift+Z
.
The
Command
pospeševalnik ne deluje v sistemih Windows ali Linux. Za našo aplikacijo za ključe z geslom moramo dodatiFile
element menija, ki ponuja dva ukaza:
... { label: 'File', submenu: [ { label: 'Create Password', accelerator: 'CmdOrCtrl+N', click: function() { ipc.send('toggle-insert-view'); } }, { type: 'separator' // to create a visual separator }, { label: 'Quit', accelerator: 'CmdOrCtrl+Q', selector: 'terminate:' // OS X only!!! } ] } ...
Ključne točke:
type
dodamo element lastnost nastavljena na separator
.CmdOrCtrl
Accelerator je združljiv s tipkovnicami Mac in PCselector
lastnina je združljiva samo z OSX!Verjetno ste v različnih primerih kode opazili sklice na imena razredov, ki se začnejo z mdl-
Za namen te vaje sem se odločil za uporabo Material Design Lite Okvir uporabniškega vmesnika, vendar lahko uporabite poljubno ogrodje uporabniškega vmesnika po vaši izbiri.
Vse, kar lahko naredimo s HTML5, lahko naredimo v Electronu; ne pozabite le naraščajoče velikosti binarnih datotek aplikacije in posledičnih težav z zmogljivostjo, ki se lahko pojavijo, če uporabljate preveč neodvisnih knjižnic.
Naredili ste aplikacijo Electron, izgleda čudovito, svoje teste e2e ste napisali z Selen in WebDriver , in pripravljeni ste ga distribuirati po svetu!
A vseeno ga želite prilagoditi, mu dati ime po meri, ki ni privzeto 'Electron', in morda tudi zagotoviti ikone po meri za platforme Mac in PC.
Te dni obstaja Gutljaj vtičnik za vse, kar si lahko omislimo. Vse kar sem moral storiti je, da vtipkam gulp electron
v Googlu in zagotovo obstaja požirek elektrona vključiti!
Ta vtičnik je dober enostaven za uporabo dokler se je ohranila struktura map, opisana na začetku te vadnice. Če ne, boste morda morali stvari malo premakniti.
Ta vtičnik je mogoče namestiti kot kateri koli drug vtičnik Gulp:
$ npm install gulp-electron --save-dev
In potem lahko svojo nalogo Gulp definiramo kot tako:
var gulp = require('gulp'), electron = require('gulp-electron'), info = require('./src/package.json'); gulp.task('electron', function() { gulp.src('') .pipe(electron({ src: './src', packageJson: info, release: './dist', cache: './cache', version: 'v0.31.2', packaging: true, platforms: ['win32-ia32', 'darwin-x64'], platformResources: { darwin: { CFBundleDisplayName: info.name, CFBundleIdentifier: info.bundle, CFBundleName: info.name, CFBundleVersion: info.version }, win: { 'version-string': info.version, 'file-version': info.version, 'product-version': info.version } } })) .pipe(gulp.dest('')); });
Ključne točke:
src/
mapa ne more biti enaka mapi, v kateri je Gulpfile.js, niti iste mape kot mapa za distribucijo.platforms
lahko določimo platforme, v katere želimo izvoziti matriko.cache
mapo, kamor bodo naložene binarne datoteke Electron, da jih bomo lahko pakirali z našo aplikacijo.packageJson
lastnine.packaging
lastnost, ki nam omogoča tudi ustvarjanje zip arhivov ustvarjenih aplikacij.Eden od platformResources
lastnosti je icon
lastnost, ki nam omogoča, da določimo ikono po meri za našo aplikacijo:
'icon': 'keychain.ico'
OS X zahteva ikone z znakom
.icns
končnico datoteke. Obstaja več spletnih orodij, ki nam omogočajo pretvorbo.png
datoteke v.ico
in.icns
zastonj.
V tem članku smo samo opraskali površino tega, kar Electron dejansko lahko stori. Pomislite na odlične aplikacije, kot sta Atom ali Ohlapnost kot vir navdiha, kamor lahko greste s tem orodjem.
Upam, da vam je bila ta vadnica koristna, pustite svoje komentarje in delite svoje izkušnje z Electronom!