這里我為" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網站運營 > 使用Electron開發(fā)記事本

使用Electron開發(fā)記事本

時間:2023-05-26 02:36:01 | 來源:網站運營

時間:2023-05-26 02:36:01 來源:網站運營

使用Electron開發(fā)記事本:

使用Electron開發(fā)記事本

Electron是一個跨平臺的框架,可以用網頁語言來開發(fā)客戶端程序,雖然說每一個應用都是一個Chrome,但畢竟也是方便了我們這些前端開發(fā)者做自己的客戶端軟件的夢想。

這里我為了能使用到最新版本的Electron,并沒有選擇用electron-vue去作為項目的基礎模版,而是在github上著了一個加了webpack功能的模版,輸入以下命令開始:

git clone git@github.com:szwacz/electron-boilerplate.git life-memory

一、測試模版是否可用

下載好之后,第一步就是將electron的版本更新到v7.1.7看看是否可以正常運行,這里為了避免因為網絡問題導致下載失敗就直接用cnpm進行安裝了。

經過測試,這個模版的運行及打包均沒有問題,可以正常執(zhí)行(Mac環(huán)境),這下子可以安心地去開發(fā)了。

二、為應用添加菜單

模版中,應用的菜單并不符合記事本的要求,因此需要調整一下。菜單的定義位于src/menu目錄下,我們要做兩件事,一是為Mac系統(tǒng)的菜單騰出第一個位置,二是補充自己需要的菜單項。下面是我的菜單項定義:

// file_menu_template.js?import { dialog } from 'electron'import log from 'electron-log'?export const fileMenuTemplate = { label: '文件', submenu: [ // { // label: '新建', // accelerator: 'CmdOrCtrl+N' // }, { label: '打開', accelerator: 'CmdOrCtrl+O', click: openFile }, { type: 'separator' }, { label: '保存', accelerator: 'CmdOrCtrl+S', click: saveFile }, { label: '另存為', accelerator: 'CmdOrCtrl+Shift+S', click: saveAsFile } ]}?export const macAppMenuTemplate = { label: '生活記', submenu: [ { label: '退出', role: 'quit' } ]}?/** * 打開文件 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function openFile(menuItem, browserWindow, event) { dialog.showOpenDialog(browserWindow, { title: '打開文件', filters: [ { name: 'Markdown 文件', extensions: ['md', 'markdown'] }, { name: '文本文件', extensions: ['txt'] } ], properties: ['openFile'] }).then(dialogRes => { if (!dialogRes.canceled) { // 向當前獲取焦點的窗口發(fā)送事件 if (browserWindow) { browserWindow.webContents.send('lm-open-file', dialogRes.filePaths) } } }).catch(e => { log.error(e) })}?/** * 保存文件 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function saveFile(menuItem, browserWindow, event) { if (browserWindow) { browserWindow.webContents.send('lm-save-file') }}?/** * 另存為 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function saveAsFile(menuItem, browserWindow, event) { if (browserWindow) { browserWindow.webContents.send('lm-save-as-file') }}?因為第一個位置暫時也不需要添加其他內容,所以我就沒有將其拆分出去,而是和文件菜單放在一個文件里了。

寫這篇文檔時項目已經完成,所以這個文檔的代碼中會包含一些現(xiàn)在用不到的代碼,見諒見諒~
// edit_menu_template.js?export const editMenuTemplate = { label: "編輯", submenu: [ { label: "撤銷", accelerator: "CmdOrCtrl+Z", click: undo }, { label: "重做", accelerator: "Shift+CmdOrCtrl+Z", click: redo }, { type: "separator" }, { label: "剪切", accelerator: "CmdOrCtrl+X", selector: "cut:" }, { label: "復制", accelerator: "CmdOrCtrl+C", selector: "copy:" }, { label: "粘貼", accelerator: "CmdOrCtrl+V", selector: "paste:" }, { label: "全選", accelerator: "CmdOrCtrl+A", click: selectAll } ]};?/** * 選擇全部 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function selectAll(menuItem, browserWindow, event) { if (browserWindow) { browserWindow.webContents.send('lm-select-all') }}?/** * 撤銷 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function undo(menuItem, browserWindow, event) { if (browserWindow) { browserWindow.webContents.send('lm-undo') }}?/** * 重做 * @param {MenuItem} menuItem 菜單項 * @param {BrowserWindow} browserWindow 渲染進程窗口 * @param {Event} event 事件 */function redo(menuItem, browserWindow, event) { if (browserWindow) { browserWindow.webContents.send('lm-redo') }}?編輯菜單里面基本上都是對文檔內容的快捷操作。

// help_menu_template.js?import { app, shell } from "electron";import jetpack from "fs-jetpack";?const appDir = jetpack.cwd(app.getAppPath());const manifest = appDir.read("package.json", "json");?export const helpMenuTemplate = { label: '幫助', submenu: [ { label: '學習Markdown語法', click: function (item, focusedWindow) { // 打開外部文檔 shell.openExternal('https://www.runoob.com/markdown/md-tutorial.html') } }, // { // label: '幫助' // }, { label: '關于', submenu: [ { label: '版本 v' + manifest.version, enabled: false } // { // label: '更新記錄' // } ] } ]}?幫助菜單中則是將應用的版本號顯示出來,另外還有一個開發(fā)時顯示的菜單,那個菜單只需要去掉退出應用的菜單項即可。

菜單定義之后,在background.js中,我們需要將新增的菜單定義加入,并稍微修改一下邏輯,讓Mac系統(tǒng)下的菜單列表前面增加一個占位的菜單。

import { devMenuTemplate } from "./menu/dev_menu_template";import { editMenuTemplate } from "./menu/edit_menu_template";import { macAppMenuTemplate, fileMenuTemplate} from "./menu/file_menu_template";import { helpMenuTemplate } from "./menu/help_menu_template";?const setApplicationMenu = () => { const menus = [fileMenuTemplate, editMenuTemplate, helpMenuTemplate]; if (process.platform === "darwin") { menus.unshift(macAppMenuTemplate); } if (env.name === "development") { menus.push(devMenuTemplate); } Menu.setApplicationMenu(Menu.buildFromTemplate(menus));};此時運行程序,我們定義的菜單就會如期顯示出來,接下來要讓程序對用戶點擊菜單項做出響應,則需要在菜單定義中定義click函數,普通的菜單點擊,我們只需要將事件發(fā)送到當前聚焦的窗口,讓它去處理這個事件即可。

不過這里就涉及到主線程主動向渲染進程發(fā)送消息的知識了,在上面的代碼中我們也可以看到,我們需要拿到browserWindow的實例,然后獲取到它的webContents對象,然后就可以向其發(fā)送消息了。而渲染進程要接受消息,則是通過ipcRenderer去獲取,這一點官方文檔已經講得很詳細了,我就不再細說了。

還有一種更為復雜的情況,以打開文件為例,當用戶點擊打開時,程序應該彈出窗口詢問用戶要打開哪個文件。而對話框只能由主線程來操作,當前菜單點擊的處理線程正是主線程,你不可能說把事件傳給渲染進程,再讓渲染進程把打開對話框的事件傳給你。所以最好還是直接就在這里彈出對話框,將用戶選擇的文件交給渲染進程處理就好了。這段代碼在上面的菜單定義中也有提及。

三、為應用添加日志記錄功能

軟件開發(fā)過程中,不可避免會遇到bug,而當bug到達用戶那里時,身為開發(fā)者的你是不好去調試的。所以日志記錄就顯得尤為關鍵,還好electron生態(tài)中有比較好用的electron-log可以使用。我的用法比較簡單,就在主線程中修改了日志記錄的格式,后面因為全局共享一個實例,所以其他地方就不用去修改配置了,直接引入這個包即可。

import log from "electron-log";?// 修改日志記錄的格式log.transports.console.format = "[{h}:{i}:{s}.{ms}] [{level} {processType}] ? {text}";log.transports.file.format = "[{y}-{m}-q9v2uis {h}:{i}:{s}.{ms}] [{level}] {text}";log.debug("path of user data: ", app.getPath("userData"));在啟動時我還去打印了一下用戶數據的存放位置,方便以后排查問題。

四、其他關鍵點記錄

其實我的最終目標不是開發(fā)一個簡單的記事本,所以我在項目中引入了CodeMirror這個插件,引入的時候還是遇到了一些問題的,下面是我的解決方案:

首先在js文件中實例化CodeMirror:

import CodeMirror from "codemirror/lib/codemirror";import "codemirror/mode/markdown/markdown";?this.editor = CodeMirror.fromTextArea( document.getElementById(textareaId), editorOptions );到這一步還是正常的,可當我要引入它的CSS文件時,它就報錯了,我也不知道為什么。但最后想出了一個解決辦法,就是把css文件在html中引入:

<!-- app/app.html -->?<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">這樣做之后基本上就沒什么問題了,關于記事本的代碼其實很簡單,邏輯也不復雜,就不貼出來獻丑了。

另外就是涉及到文件讀寫時,node的文件系統(tǒng)讀寫結果是通過回調函數來獲取的,我覺得用起來很不爽,就寫了一個工具類把它包裝了一下,讓它返回Promise對象。然后我用的時候就可以愉快的用async/await了~

最后一點就是我比較喜歡用scss去寫樣式文件,所以需要自己配置一下scss的編譯方式,首先需要安裝sass:

cnpm i sass node-sass sass-loader --save-dev安裝之后,找到build/webpack.base.config.js,在rules中添加:

{ test: //.scss$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' } ] }這樣就可以解析scss文件了。

五、打包相關

1、圖標

應用做好之后,我們需要為其準備一個精美的圖標,而在不同的系統(tǒng)上使用的圖標類型是不同的,因此我們在得到一張1024x1024.png的圖標之后,還需要為windows平臺生成.ico格式的圖標,此時我們可以在https://www.easyicon.net/language.en/covert/這個網站去轉換。

若要為Mac平臺生成.icns的圖標則沒有那么簡單,因為icns格式并不是一個圖標,而是包含不同分辨率圖標的集合,我們需要一個一個的生成然后再去轉換。

我就填了這個坑,我在剛剛的網站把轉換好的一張icns格式的圖片放到項目中打包,結果打包后的應用是沒有圖標的!
轉換icns并沒有網站可以幫我們做,我們只能在mac電腦中敲命令來做。具體可以參考這個博客,需要注意的是剛開始創(chuàng)建的目錄,后面的.iconset不能省,前面的名字可以隨便起。

當圖標準備完畢之后,把它們重命名替換掉項目中resources目錄下的圖標文件即可。

2、為程序關聯(lián)文件格式

我希望我的程序在安裝過后可以在用戶想要打開文本文件時可以用我的程序來打開,可在Mac系統(tǒng)上,你會發(fā)現(xiàn)大部分應用處于灰色狀態(tài)(如果你的應用不做處理,也會是這個樣子的)







為了這個小功能我谷歌了好久好久都沒找到解決方案,不過最后偶然間看到了Electron-bilder的配置文檔,里面描述了如何配置文件關聯(lián),我只能說,,真NM簡單。。

Electron-builder的配置一般會放在packages.json中,恰好我用的這個模版里面的打包工具就是它,我們只需要在build下面加上下面的配置即可關聯(lián)自己定義的文件格式了。

"fileAssociations": [ { "ext": "md", "name": "Markdown 文件", "role": "Editor" }, { "ext": "markdown", "name": "Markdown 文件", "role": "Editor" }, { "ext": "txt", "name": "文本文件", "role": "Editor" } ],關聯(lián)之后,程序只是虛有其表,因為我們并沒有真正去處理傳來的文件,所以下一步就是接收文件路徑。在這一步自己也爬了一個又一個坑,都是血和淚的教訓啊。。。

在程序啟動時接收文件路徑參數,乍一想這個問題,就應該是通過進程對象就可以取到了??僧敃r我在Mac電腦上開發(fā),不論怎么搞都沒辦法獲取到路徑參數,谷歌也找不到答案。又是在萬念俱灰之時,我去看了看官方文檔,,,我只想說MMP

原來,Mac系統(tǒng)是要監(jiān)聽app的open-file事件的,而Windows則是通過進程對象來獲取文件路徑。







這樣可以獲取到文件路徑了,但最終這個路徑是要交給渲染進程去處理的,而在程序剛啟動時渲染進程甚至還沒有創(chuàng)建出來!此時,就需要在主進程中先定義一個變量保存一下接收的這個路徑了,等待渲染進程加載完成后再把這個路徑傳給它,所以,我的整個處理邏輯如下:

// background.js?// 外部文件路徑let preFilePath = ''?app.on('will-finish-launching', () => { log.debug('will-finish-launching')? // 打開文件事件(MacOS有效) app.on("open-file", (e, filePath) => { log.debug("open-file: ", filePath);? const fw = BrowserWindow.getFocusedWindow(); if (fw) { fw.webContents.send("lm-open-file", [filePath]); } else { preFilePath = filePath } });? // 檢查進程是否含有參數(Windows有效) if (process.platform ==='win32' && process.argv.length >= 2) { log.debug('process argv:', process.argv)? // windows系統(tǒng)當沒有路徑參數時這個位置默認有個.,需要加以判斷 preFilePath = process.argv[1] === '.' ? '' : process.argv[1] }})?mainWindow.once('ready-to-show', () => { log.debug('ready-to-show') mainWindow.show()? // 檢查是否存在需要直接打開的文件,有的話就直接打開 if (preFilePath) { mainWindow.webContents.send('lm-open-file', [preFilePath]) } })其中,在app的will-finish-launching事件中才開始監(jiān)聽文件打開事件,也是官方文檔上面建議的:







這樣做了之后,整個記事本應用才顯得完整起來。

其實,上面的很多做法不僅限于記事本中使用,希望我寫的文章能對大家有所幫助!

下面放上我寫的記事本的截圖,來證明我做到過!






關鍵詞:記事,使用

74
73
25
news

版權所有? 億企邦 1997-2025 保留一切法律許可權利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關閉