الإلكترون: أصبحت تطبيقات سطح المكتب عبر الأنظمة الأساسية سهلة

نشرت: 2022-03-11

في وقت سابق من هذا العام ، أصدرت Github Atom-Shell ، جوهر محررها الشهير مفتوح المصدر Atom ، وأعاد تسميتها إلى Electron للمناسبة الخاصة.

على عكس المنافسين الآخرين في فئة تطبيقات سطح المكتب المستندة إلى Node.js ، يجلب Electron لمسة خاصة به إلى هذا السوق الراسخ بالفعل من خلال الجمع بين قوة Node.js (io.js حتى الإصدارات الأخيرة) مع محرك Chromium لجلب لنا الأفضل من كل من الخادم وجافا سكريبت من جانب العميل.

تخيل عالماً يمكننا فيه بناء تطبيقات سطح مكتب عالية الأداء ومدعومة بالبيانات وعبر الأنظمة الأساسية مدعومة ليس فقط من خلال المستودع المتزايد باستمرار لوحدات NPM ، ولكن أيضًا سجل Bower بأكمله لتلبية جميع احتياجات جانب العميل.

أدخل الكترون.

بناء تطبيقات سطح المكتب عبر الأنظمة الأساسية باستخدام الإلكترون

بناء تطبيقات سطح المكتب عبر الأنظمة الأساسية باستخدام الإلكترون
سقسقة

في هذا البرنامج التعليمي ، سننشئ تطبيقًا بسيطًا لسلسلة مفاتيح كلمات المرور باستخدام Electron و Angular.js و Loki.js ، وهي قاعدة بيانات خفيفة الوزن وداخل الذاكرة مع بناء جملة مألوف لمطوري MongoDB.

كود المصدر الكامل لهذا التطبيق متاح هنا.

يفترض هذا البرنامج التعليمي أن:

  • القارئ لديه Node.js و Bower مثبتين على أجهزتهم.
  • هم على دراية بـ Node.js و Angular.js وصيغة استعلام تشبه MongoDB.

الحصول على البضائع

أول الأشياء أولاً ، سنحتاج إلى الحصول على ثنائيات الإلكترون لاختبار تطبيقنا محليًا. يمكننا تثبيته عالميًا واستخدامه كـ CLI ، أو تثبيته محليًا في مسار تطبيقنا. أوصي بتثبيته عالميًا ، وبهذه الطريقة لا يتعين علينا القيام بذلك مرارًا وتكرارًا لكل تطبيق نقوم بتطويره.

سنتعلم لاحقًا كيفية حزم تطبيقنا للتوزيع باستخدام Gulp. تتضمن هذه العملية نسخ ثنائيات الإلكترون ، وبالتالي لا معنى لتثبيتها يدويًا في مسار تطبيقنا.

لتثبيت Electron CLI ، يمكننا كتابة الأمر التالي في طرفنا:

 $ npm install -g electron-prebuilt

لاختبار التثبيت ، اكتب electron -h ويجب أن تعرض إصدار Electron CLI.

في وقت كتابة هذا المقال ، كان إصدار الإلكترون 0.31.2 .

إنشاء المشروع

لنفترض بنية المجلد الأساسية التالية:

 my-app |- cache/ |- dist/ |- src/ |-- app.js | gulpfile.js

... حيث: - سيتم استخدام ذاكرة التخزين المؤقت / لتنزيل ثنائيات الإلكترون عند إنشاء التطبيق. - سيحتوي التوزيع / على ملفات التوزيع المُنشأة. - سيحتوي src / على الكود المصدري الخاص بنا. - سيكون src / app.js نقطة دخول تطبيقنا.

بعد ذلك ، سننتقل إلى المجلد src/ في الجهاز الطرفي الخاص بنا وننشئ ملفات package.json و bower.json :

 $ npm init $ bower init

سنقوم بتثبيت الحزم الضرورية لاحقًا في هذا البرنامج التعليمي.

فهم عمليات الإلكترون

يميز الإلكترون بين نوعين من العمليات:

  • العملية الرئيسية : نقطة دخول تطبيقنا ، الملف الذي سيتم تنفيذه كلما قمنا بتشغيل التطبيق. عادةً ما يعلن هذا الملف عن النوافذ المختلفة للتطبيق ، ويمكن استخدامه اختياريًا لتحديد مستمعي الأحداث العالمية باستخدام وحدة IPC الخاصة بـ Electron.
  • عملية العارض : وحدة التحكم لنافذة معينة في تطبيقنا. تقوم كل نافذة بإنشاء عملية العارض الخاصة بها.

لتوضيح الكود ، يجب استخدام ملف منفصل لكل عملية من عمليات العارض. لتحديد العملية الرئيسية لتطبيقنا ، src/app.js وحدة app لبدء التطبيق ، ووحدة browser-window لإنشاء النوافذ المختلفة لتطبيقنا (كلاهما جزء من Electron core) ، كما:

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

عند بدء تشغيل التطبيق فعليًا ، فإنه يطلق حدثًا ready يمكننا الارتباط به. في هذه المرحلة ، يمكننا إنشاء مثيل للنافذة الرئيسية لتطبيقنا:

 var mainWindow = null; app.on('ready', function() { mainWindow = new BrowserWindow({ width: 1024, height: 768 }); mainWindow.loadUrl('file://' + __dirname + '/windows/main/main.html'); mainWindow.openDevTools(); });

النقاط الرئيسية:

  • نقوم بإنشاء نافذة جديدة عن طريق إنشاء مثيل جديد لكائن BrowserWindow .
  • يأخذ كائنًا كوسيطة واحدة ، مما يسمح لنا بتحديد إعدادات مختلفة ، من بينها العرض والارتفاع الافتراضيان للنافذة.
  • يحتوي مثيل النافذة على طريقة loadUrl() ، مما يسمح لنا بتحميل محتويات ملف HTML الفعلي في النافذة الحالية. يمكن أن يكون ملف HTML محليًا أو بعيدًا .
  • يحتوي مثيل النافذة على طريقة openDevTools() اختيارية ، مما يسمح لنا بفتح مثيل من Chrome Dev Tools في النافذة الحالية لأغراض تصحيح الأخطاء.

بعد ذلك ، يجب علينا تنظيم الكود الخاص بنا قليلاً. أوصي بإنشاء windows/ مجلد في src/ folder ، وحيث يمكننا إنشاء مجلد فرعي لكل نافذة ، على النحو التالي:

 my-app |- src/ |-- windows/ |--- main/ |---- main.controller.js |---- main.html |---- main.view.js

... حيث main.controller.js على منطق "جانب الخادم" main.view.js على منطق "جانب العميل" لتطبيقنا.

ملف main.html هو مجرد صفحة ويب HTML5 ، لذلك يمكننا ببساطة بدء تشغيله على النحو التالي:

 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Password Keychain</title> </head> <body> <h1>Password Keychain</h1> </body> </html>

في هذه المرحلة ، يجب أن يكون تطبيقنا جاهزًا للتشغيل. لاختباره ، يمكننا ببساطة كتابة ما يلي في جهازك الطرفي ، في جذر مجلد src :

 $ electron .

يمكننا أتمتة هذه العملية عن طريق تحديد سكربت start لملف package.son.

بناء تطبيق Password Keychain لسطح المكتب

لإنشاء تطبيق Keychain لكلمة المرور ، نحتاج إلى: - طريقة لإضافة كلمات المرور وتوليدها وحفظها. - طريقة مناسبة لنسخ وإزالة كلمات المرور.

توليد وحفظ كلمات المرور

نموذج بسيط يكفي لإدخال كلمات مرور جديدة. من أجل إظهار الاتصال بين النوافذ المتعددة في Electron ، ابدأ بإضافة نافذة ثانية في تطبيقنا ، والتي ستعرض نموذج "insert". نظرًا لأننا سنفتح هذه النافذة ونغلقها عدة مرات ، يجب أن نختتم المنطق بطريقة ما حتى نتمكن من الاتصال به عند الحاجة:

 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; }); }

النقاط الرئيسية:

  • سنحتاج إلى ضبط خاصية show على false في كائن الخيارات من مُنشئ BrowserWindow ، من أجل منع فتح النافذة افتراضيًا عند بدء تشغيل التطبيقات.
  • سنحتاج إلى تدمير مثيل BrowserWindow عندما تطلق النافذة حدثًا مغلقًا .

فتح وإغلاق نافذة "الإدراج"

الفكرة هي أن تكون قادرًا على تشغيل نافذة "الإدراج" عندما ينقر المستخدم النهائي على زر في النافذة "الرئيسية". للقيام بذلك ، سنحتاج إلى إرسال رسالة من النافذة الرئيسية إلى العملية الرئيسية لإرشادها لفتح نافذة الإدراج. يمكننا تحقيق ذلك باستخدام وحدة IPC الخاصة بـ Electron. يوجد في الواقع نوعان مختلفان من وحدة IPC:

  • واحد للعملية الرئيسية ، مما يسمح للتطبيق بالاشتراك في الرسائل المرسلة من النوافذ.
  • واحد لعملية العارض ، مما يسمح للتطبيق بإرسال رسائل إلى العملية الرئيسية.

على الرغم من أن قناة اتصال Electron هي في الغالب أحادية الاتجاه ، فمن الممكن الوصول إلى وحدة IPC للعملية الرئيسية في عملية Renderer من خلال استخدام الوحدة النمطية البعيدة. أيضًا ، يمكن للعملية الرئيسية إرسال رسالة مرة أخرى إلى عملية العارض التي نشأ منها الحدث باستخدام طريقة Event.sender.send ().

لاستخدام وحدة IPC ، نطلبها فقط مثل أي وحدة NPM أخرى في البرنامج النصي للعملية الرئيسية:

 var ipc = require('ipc');

... ثم اربط بالأحداث باستخدام طريقة on() :

 ipc.on('toggle-insert-view', function() { if(!insertWindow) { createInsertWindow(); } return (!insertWindow.isClosed() && insertWindow.isVisible()) ? insertWindow.hide() : insertWindow.show(); });

النقاط الرئيسية:

  • يمكننا تسمية الحدث كما نريد ، المثال تعسفي فقط.
  • لا تنس التحقق مما إذا كان قد تم إنشاء مثيل BrowserWindow بالفعل ، إذا لم يكن كذلك ، فقم بإنشاء مثيل له.
  • يحتوي مثيل BrowserWindow على بعض الطرق المفيدة:
    • isClosed () يعيد قيمة منطقية ، سواء كانت النافذة حاليًا في حالة closed أم لا.
    • isVisible () : إرجاع قيمة منطقية ، سواء كانت النافذة مرئية حاليًا أم لا.
    • show () / hide () : طرق ملائمة لإظهار وإخفاء النافذة.

نحتاج الآن بالفعل إلى إطلاق هذا الحدث من عملية Renderer. سننشئ ملف نصي جديد يسمى main.view.js ، ونضيفه إلى صفحة HTML الخاصة بنا كما نفعل مع أي برنامج نصي عادي:

 <script src="./main.view.js"></script>

يؤدي تحميل ملف البرنامج النصي عبر علامة script HTML إلى تحميل هذا الملف في سياق جانب العميل. هذا يعني ، على سبيل المثال ، المتغيرات العامة متاحة عبر window.<varname> . لتحميل نص برمجي في سياق من جانب الخادم ، يمكننا استخدام طريقة require() مباشرة في صفحة HTML الخاصة بنا: require('./main.controller.js'); .

على الرغم من تحميل البرنامج النصي في سياق جانب العميل ، لا يزال بإمكاننا الوصول إلى وحدة IPC لعملية العارض بنفس الطريقة التي يمكننا بها للعملية الرئيسية ، ثم إرسال الحدث الخاص بنا على هذا النحو:

 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'); }); }; });

هناك أيضًا طريقة sendSync () متاحة ، في حال احتجنا إلى إرسال أحداثنا بشكل متزامن.

الآن ، كل ما تبقى لنا لفتح نافذة "insert" هو إنشاء زر HTML مع التوجيه Angular المطابق عليه:

 <div ng-controller="MainCtrl as vm"> <button toggle-insert-view class="mdl-button"> <i class="material-icons">add</i> </button> </div>

وأضف هذا التوجيه باعتباره تبعية لوحدة التحكم الزاويّة للنافذة الرئيسية:

 angular .module('MainWindow', ['Utils']) .controller('MainCtrl', function() { var vm = this; }); 

توليد كلمات المرور

لتبسيط الأمور ، يمكننا فقط استخدام وحدة NPM uuid لإنشاء معرفات فريدة من شأنها أن تكون بمثابة كلمات مرور لغرض هذا البرنامج التعليمي. يمكننا تثبيته مثل أي وحدة NPM أخرى ، وطلبه في البرنامج النصي "Utils" الخاص بنا ، ثم إنشاء مصنع بسيط سيعيد معرفًا فريدًا:

 var uuid = require('uuid'); angular .module('Utils', []) ... .factory('Generator', function() { return { create: function() { return uuid.v4(); } }; })

الآن ، كل ما تبقى لنا هو إنشاء زر في عرض الإدراج ، وإرفاق توجيه به يستمع إلى النقر فوق الأحداث على الزر واستدعاء طريقة create ():

 <!-- in insert.html --> <button generate-password class="mdl-button">generate</button>
 // 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(); }); }; }])

حفظ كلمات المرور

في هذه المرحلة ، نريد تخزين كلمات المرور الخاصة بنا. هيكل البيانات لإدخالات كلمة المرور الخاصة بنا بسيط إلى حد ما:

 { "id": String "description": String, "username": String, "password": String }

لذلك كل ما نحتاجه حقًا هو نوع من قاعدة البيانات في الذاكرة التي يمكن مزامنتها اختياريًا مع ملف للنسخ الاحتياطي. لهذا الغرض ، يبدو أن Loki.js هو المرشح المثالي. إنه يفعل بالضبط ما نحتاجه لغرض هذا التطبيق ، ويقدم علاوة على ذلك ميزة Dynamic Views ، مما يسمح لنا بالقيام بأشياء مشابهة لوحدة تجميع MongoDB.

لا تقدم طرق العرض الديناميكية جميع الوظائف التي توفرها وحدة تجميع MongodDB. يرجى الرجوع إلى الوثائق لمزيد من المعلومات.

لنبدأ بإنشاء نموذج HTML بسيط:

 <div class="insert" ng-controller="InsertCtrl as vm"> <form name="insertForm" no-validate> <fieldset ng-disabled="!vm.loaded"> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="text" ng-model="vm.formData.description" required /> <label class="mdl-textfield__label" for="description">Description...</label> </div> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="text" ng-model="vm.formData.username" /> <label class="mdl-textfield__label" for="username">Username...</label> </div> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="password" ng-model="vm.formData.password" required /> <label class="mdl-textfield__label" for="password">Password...</label> </div> <div class=""> <button generate-password class="mdl-button">generate</button> <button toggle-insert-view class="mdl-button">cancel</button> <button save-password class="mdl-button" ng-disabled="insertForm.$invalid">save</button> </div> </fieldset> </form> </div>

والآن ، دعنا نضيف منطق JavaScript للتعامل مع نشر وحفظ محتويات النموذج:

 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'); }); } }); }; }])

النقاط الرئيسية:

  • نحتاج أولاً إلى تهيئة قاعدة البيانات. تتضمن هذه العملية إنشاء مثيل جديد لكائن Loki ، وتوفير المسار إلى ملف قاعدة البيانات كوسيطة ، والبحث عما إذا كان ملف النسخ الاحتياطي موجودًا ، وإنشائه إذا لزم الأمر (بما في ذلك مجموعة "Keychain") ، ثم تحميل محتويات هذا الملف في الذاكرة.
  • يمكننا استرداد مجموعة معينة في قاعدة البيانات باستخدام طريقة getCollection() .
  • يكشف كائن المجموعة عن عدة طرق ، بما في ذلك طريقة insert() ، مما يسمح لنا بإضافة مستند جديد إلى المجموعة.
  • لاستمرار محتويات قاعدة البيانات إلى ملف ، يعرض كائن Loki أسلوب saveDatabase() .
  • سنحتاج إلى إعادة تعيين بيانات النموذج وإرسال حدث IPC لإخبار العملية الرئيسية بإغلاق النافذة بمجرد حفظ المستند.

لدينا الآن نموذج بسيط يسمح لنا بإنشاء كلمات مرور جديدة وحفظها. دعنا نعود إلى العرض الرئيسي لسرد هذه الإدخالات.

سرد كلمات المرور

يجب أن تحدث بعض الأشياء هنا:

  • نحتاج إلى أن نكون قادرين على الحصول على جميع المستندات الموجودة في مجموعتنا.
  • نحتاج إلى إعلام العرض الرئيسي متى تم حفظ كلمة مرور جديدة حتى يمكن تحديث العرض.

يمكننا استرداد قائمة المستندات عن طريق استدعاء طريقة getCollection() على كائن Loki. تُرجع هذه الطريقة كائنًا بخاصية تسمى البيانات ، وهي ببساطة مصفوفة من جميع المستندات في تلك المجموعة:

 this.getCollection = function() { this.collection = this.db.getCollection('keychain'); return this.collection; }; this.getDocs = function() { return (this.getCollection()) ? this.getCollection().data : null; };

يمكننا بعد ذلك استدعاء getDocs () في وحدة التحكم Angular الخاصة بنا واسترداد جميع كلمات المرور المخزنة في قاعدة البيانات ، بعد أن نقوم بتهيئتها:

 angular .module('MainView', ['Utils']) .controller('MainCtrl', ['Storage', function(Storage) { var vm = this; vm.keychain = null; Storage .init() .then(function(db) { vm.keychain = db.getDocs(); }); });

القليل من القوالب الزاويّة ، ولدينا قائمة بكلمات المرور:

 <tr ng-repeat="item in vm.keychain track by $index" class="item--{{$index}}"> <td class="mdl-data-table__cell--non-numeric">{{item.description}}</td> <td>{{item.username || 'n/a'}}</td> <td> <span ng-repeat="n in [1,2,3,4,5,6]">&bull;</span> </td> <td> <a href="#" copy-password="{{$index}}">copy</a> <a href="#" remove-password="{{item}}">remove</a> </td> </tr> 

من الميزات الرائعة المضافة تحديث قائمة كلمات المرور بعد إدخال كلمة مرور جديدة. لهذا ، يمكننا استخدام وحدة IPC الخاصة بـ Electron. كما ذكرنا سابقًا ، يمكن استدعاء وحدة IPC للعملية الرئيسية في عملية العارض لتحويلها إلى عملية مستمع ، باستخدام الوحدة النمطية البعيدة. فيما يلي مثال على كيفية تنفيذه في 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(); }); }); }); }]);

النقاط الرئيسية:

  • سنحتاج إلى استخدام الوحدة البعيدة عبر طريقة require() الخاصة بها لطلب وحدة IPC البعيدة من العملية الرئيسية.
  • يمكننا بعد ذلك إعداد عملية Renderer الخاصة بنا كمستمع للأحداث عبر طريقة on() ، وربط وظائف رد الاتصال بهذه الأحداث.

سيكون عرض الإدراج بعد ذلك مسؤولاً عن إرسال هذا الحدث كلما تم حفظ مستند جديد:

 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'); });

نسخ كلمات المرور

ليس من الجيد عادةً عرض كلمات المرور بنص عادي. بدلاً من ذلك ، سنخفي ونوفر زرًا ملائمًا يسمح للمستخدم النهائي بنسخ كلمة المرور مباشرة لإدخال معين.

هنا مرة أخرى ، يأتي Electron لإنقاذنا من خلال تزويدنا بوحدة حافظة بأساليب سهلة لنسخ ولصق ليس فقط محتوى النص ، ولكن أيضًا الصور ورمز 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); }); }; }]);

نظرًا لأن كلمة المرور التي تم إنشاؤها ستكون سلسلة بسيطة ، يمكننا استخدام طريقة writeText() لنسخ كلمة المرور إلى حافظة النظام. يمكننا بعد ذلك تحديث عرض HTML الرئيسي الخاص بنا ، وإضافة زر النسخ مع توجيه copy-password عليه ، مما يوفر فهرس مجموعة كلمات المرور:

 <a href="#" copy-password="{{$index}}">copy</a>

إزالة كلمات المرور

قد يرغب المستخدمون النهائيون لدينا أيضًا في أن يتمكنوا من حذف كلمات المرور ، في حال أصبحت قديمة. للقيام بذلك ، كل ما نحتاج إليه هو استدعاء طريقة remove() في مجموعة keychain. نحتاج إلى تقديم المستند بأكمله إلى طريقة "remove ()" ، على النحو التالي:

 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); };

تنص وثائق Loki.js على أنه يمكننا أيضًا إزالة مستند من خلال معرفه ، ولكن لا يبدو أنه يعمل كما هو متوقع.

إنشاء قائمة سطح المكتب

يتكامل Electron بسلاسة مع بيئة سطح المكتب الخاصة بنظام التشغيل لتوفير تجربة مستخدم "أصلية" مظهر وشكل لتطبيقاتنا. لذلك ، يأتي Electron مرفقًا بوحدة قائمة ، مخصصة لإنشاء هياكل قائمة سطح مكتب معقدة لتطبيقنا.

تعد وحدة القائمة موضوعًا واسعًا وتستحق تقريبًا درسًا تعليميًا خاصًا بها. أوصي بشدة بقراءة البرنامج التعليمي لتكامل بيئة سطح المكتب من Electron لاكتشاف جميع ميزات هذه الوحدة.

بالنسبة لنطاق هذا البرنامج التعليمي الحالي ، سنرى كيفية إنشاء قائمة مخصصة وإضافة أمر مخصص إليها وتنفيذ أمر quit القياسي.

إنشاء وتخصيص قائمة مخصصة لتطبيقنا

عادةً ما ينتمي منطق JavaScript لقائمة Electron إلى ملف البرنامج النصي الرئيسي لتطبيقنا ، حيث يتم تحديد عمليتنا الرئيسية. ومع ذلك ، يمكننا تجريده في ملف منفصل ، والوصول إلى وحدة القائمة عبر الوحدة النمطية البعيدة:

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

لتحديد قائمة بسيطة ، سنحتاج إلى استخدام طريقة buildFromTemplate() :

 var appMenu = Menu.buildFromTemplate([ { label: 'Electron', submenu: [{ label: 'Credits', click: function() { alert('Built with Electron & Loki.js.'); } }] } ]);

يتم دائمًا استخدام العنصر الأول في المصفوفة كعنصر قائمة "افتراضي".

لا تهم قيمة خاصية label كثيرًا بالنسبة لعنصر القائمة الافتراضي. في وضع dev ، سيعرض دائمًا Electron . سنرى لاحقًا كيفية تعيين اسم مخصص لعنصر القائمة الافتراضية أثناء مرحلة الإنشاء.

أخيرًا ، نحتاج إلى تعيين هذه القائمة المخصصة كقائمة افتراضية لتطبيقنا باستخدام طريقة setApplicationMenu() :

 Menu.setApplicationMenu(appMenu);

تعيين اختصارات لوحة المفاتيح

يوفر Electron "المسرعات" ، وهي مجموعة من السلاسل المحددة مسبقًا التي تتناسب مع مجموعات لوحة المفاتيح الفعلية ، على سبيل المثال: Command+A أو Ctrl+Shift+Z

لا يعمل برنامج تسريع Command على نظام التشغيل Windows أو Linux. بالنسبة إلى تطبيق Keychain الخاص بكلمة المرور ، يجب أن نضيف عنصر قائمة File ، مع تقديم أمرين:

  • إنشاء كلمة مرور : افتح عرض الإدراج باستخدام Cmd (أو Ctrl) + N.
  • إنهاء : قم بإنهاء التطبيق تمامًا باستخدام Cmd (أو Ctrl) + Q
 ... { 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!!! } ] } ...

النقاط الرئيسية:

  • يمكننا إضافة فاصل مرئي عن طريق إضافة عنصر إلى المصفوفة مع ضبط خاصية type على separator .
  • مسرع CmdOrCtrl متوافق مع كل من لوحات مفاتيح Mac و PC
  • خاصية selector متوافقة فقط مع OSX!

تصميم تطبيقنا

ربما لاحظت في العديد من أمثلة التعليمات البرمجية المراجع لأسماء الفئات التي تبدأ بـ mdl- . لغرض هذا البرنامج التعليمي ، اخترت استخدام إطار عمل Material Design Lite UI ، لكن لا تتردد في استخدام أي إطار عمل من اختيارك لواجهة المستخدم.

أي شيء يمكننا القيام به باستخدام HTML5 يمكن القيام به في Electron ؛ فقط ضع في اعتبارك الحجم المتزايد للثنائيات للتطبيق ، ومشكلات الأداء الناتجة التي قد تحدث إذا كنت تستخدم عددًا كبيرًا جدًا من مكتبات الجهات الخارجية.

تغليف تطبيقات الإلكترون للتوزيع

لقد أنشأت تطبيق Electron ، ويبدو رائعًا ، وقمت بكتابة اختبارات e2e باستخدام السيلينيوم و WebDriver ، وأنت على استعداد لتوزيعه على العالم!

لكنك ما زلت ترغب في تخصيصه ، ومنحه اسمًا مخصصًا بخلاف الاسم الافتراضي "Electron" ، وربما أيضًا توفير رموز تطبيقات مخصصة لمنصات Mac و PC.

البناء مع Gulp

في هذه الأيام ، هناك مكون إضافي لـ Gulp لأي شيء يمكن أن نفكر فيه. كل ما كان علي فعله هو كتابة gulp electron في Google ، وبالتأكيد هناك مكون إضافي gulp-electron!

هذا البرنامج المساعد سهل الاستخدام إلى حد ما طالما تم الحفاظ على بنية المجلد المفصلة في بداية هذا البرنامج التعليمي. إذا لم يكن الأمر كذلك ، فقد تضطر إلى تحريك الأشياء قليلاً.

يمكن تثبيت هذا المكون الإضافي مثل أي مكون إضافي لـ Gulp:

 $ npm install gulp-electron --save-dev

وبعد ذلك يمكننا تحديد مهمة Gulp الخاصة بنا على النحو التالي:

 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("")); });

النقاط الرئيسية:

  • لا يمكن أن يكون المجلد src/ هو نفسه المجلد حيث يوجد Gulpfile.js ، ولا يمكن أن يكون نفس المجلد مثل مجلد التوزيع.
  • يمكننا تحديد المنصات التي نرغب في التصدير إليها عبر مصفوفة platforms .
  • يجب أن نحدد مجلد cache ، حيث سيتم تنزيل ثنائيات الإلكترون حتى يمكن حزمها مع تطبيقنا.
  • يجب تمرير محتويات ملف package.json الخاص بالتطبيق إلى مهمة gulp عبر خاصية packageJson .
  • هناك خاصية packaging اختيارية ، تتيح لنا أيضًا إنشاء أرشيفات مضغوطة للتطبيقات التي تم إنشاؤها.
  • لكل منصة ، هناك مجموعة مختلفة من "موارد النظام الأساسي" التي يمكن تحديدها.

إضافة أيقونات التطبيق

إحدى خصائص platformResources هي خاصية Icon ، مما يسمح لنا بتحديد icon مخصص لتطبيقنا:

 "icon": "keychain.ico"

يتطلب OS X رموزًا بملحق الملف .icns . هناك العديد من الأدوات عبر الإنترنت تتيح لنا تحويل ملفات .png إلى .ico و. .icns مجانًا.

خاتمة

في هذه المقالة ، قمنا فقط بخدش سطح ما يمكن أن تفعله إلكترون بالفعل. فكر في تطبيقات رائعة مثل Atom أو Slack كمصدر للإلهام حيث يمكنك استخدام هذه الأداة.

أتمنى أن تكون قد وجدت هذا البرنامج التعليمي مفيدًا ، فلا تتردد في ترك تعليقاتك ومشاركة تجاربك مع Electron!