banner
isolcat

isolcat

I am not afraid of storms, for I am learning how to sail my ship
github

用Electron來做一個支持markdown的便箋吧!

前言#

最近換了台 MacBook Air,發現內置了一個 “便簽” 的 app,感覺蠻不錯的,平時可以用來做個每日計劃啥的,但最讓我不滿意的一個點就是不支持 markdown!導致每次下意識的去使用 markdown 語法的時候就很別扭,類似這樣:

Untitled

看著就很別扭,加上樣式也不算很美觀,誒🤓👆,不如自己 DIY 一個?說幹就幹,Electron,啟動!

架子搭好#

這部分不願意過多的去說,咱主要還是以實現這個支持 markdown 的便簽和優化功能為主,這裡直接看官方文檔即可:https://www.electronjs.org/zh/docs/latest/tutorial/quick-start

功能實現#

需求分析:支持 markdown 的便簽

根據我們自己給自己創建的需求,來做個簡單的流程圖:

Mermaid Loading...

這裡為了控制大小,就不要再引入框架了,直接使用 electron 來實現相關功能就行:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Markdown Notepad</title>
  <style>
    body {
      display: flex;
      height: 100vh;
      margin: 0;
      font-family: Arial, sans-serif;
    }

    #markdown-input,
    #markdown-preview {
      flex: 1;
      padding: 20px;
      box-sizing: border-box;
      height: 100%;
      overflow-y: auto;
    }

    #markdown-input {
      border-right: 1px solid #ddd;
    }

    #markdown-preview {
      padding-left: 40px;
    }
  </style>
</head>

<body>
  <textarea id="markdown-input" placeholder="Enter Markdown here..."></textarea>
  <div id="markdown-preview"></div>
</body>

</html>

這時候我們注意到,上方一直會有一個窗口欄在那,相較於 Mac 上的便簽來說,顯得就很不優雅,這時候就可以通過調整 main.js(負責創建窗口和處理系統事件)來修改我們創建的窗口:

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');

let win; // 修改變量名以符合下文使用

function createWindow() {
  // 創建一個無邊框的瀏覽器窗口
  win = new BrowserWindow({
    width: 320,
    height: 320,
    frame: false, // 設置窗口無邊框
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    }
  });

通過設置BrowserWindow中的 frame 屬性,便可以讓窗口邊框消失了

演示

接下來,讓我們進入下一步,即引入解析 Markdown 語法的庫。在這裡,我們選擇了 Marked。Marked 是一個功能強大的 JavaScript 庫,它可以將 Markdown 文本解析為 HTML。它的優點包括速度快,輕量級,同時它支持 Github 風格的 Markdown 語法,也支持自定義渲染。這些優點使得 Marked 成為我們的首選。

npm install marked

讓我們在 renderer.js 中處理一下前端邏輯:

mdInput.addEventListener('input', function () {
  const renderedHtml = marked.parse(mdInput.value);
  mdPreview.innerHTML = renderedHtml;
});

OK,再稍微修改一下 HTML,讓我們來看看,功能是不是實現了:

test

好了,功能沒問題!成功渲染!

進一步優化#

現在用著是不是感覺還是不太對勁?這樣子左側一塊,右側一塊的,一點都不優雅,那讓我們來修改一下,做個按鈕來切換編輯和渲染這兩個狀態:

  <div id="app-container">
    <textarea id="markdown-input" placeholder="Enter Markdown here..."></textarea>
    <div id="markdown-preview"></div>
    <div class="buttons-container">
      <button id="toggle-pin" class="toggle-button">📌 Toggle Pin</button>
      <button id="toggle-preview" class="toggle-button">👌🏻 Preview</button>
    </div>
  </div>

將前端邏輯仍然寫在 renderer.js 中,在處理這個邏輯:

togglePreviewBtn.addEventListener('click', () => {
  isPreviewMode = !isPreviewMode; // 直接切換預覽模式狀態
  if (isPreviewMode) {
    mdInput.style.display = 'none';
    mdPreview.style.display = 'block';
    togglePreviewBtn.textContent = '✏️  Edit';
  } else {
    mdInput.style.display = 'block';
    mdPreview.style.display = 'none';
    togglePreviewBtn.textContent = '👌🏻 Preview';
  }
});

OK,功能實現,相信細心的讀者已經發現了這裡還多了一個 “**📌 Toggle Pin”** 的按鈕,既然要讓他作為便利貼的存在,那自然要給他置頂的功能咯,這裡便可以利用 Electron 的一個重要功能 ——進程間通信 (IPC)

進程間通信 (IPC) 是在 Electron 中構建功能豐富的桌面應用程序的關鍵部分之一。 由於主進程和渲染器進程在 Electron 的進程模型具有不同的職責,因此 IPC 是執行許多常見任務的唯一方法,例如從 UI 調用原生 API 或從原生菜單觸發 Web 內容的更改。

這裡我們主要的思路是:"Toggle Pin" 功能通過渲染進程監聽按鈕點擊,切換窗口置頂狀態,並通過 Electron 的 IPC 機制發送消息給主進程,由主進程執行實際的置頂操作,下面是實際代碼:

// main.js

const { app, BrowserWindow, ipcMain } = require('electron');

//.....

// 監聽從渲染進程發來的toggle-pin消息
ipcMain.on('toggle-pin', (event, shouldPin) => {
  if (win) {
    win.setAlwaysOnTop(shouldPin); // 設置窗口是否置頂
  }
});

// renderer.js
togglePinBtn.addEventListener('click', () => {
  isWindowPinned = !isWindowPinned;
  ipcRenderer.send('toggle-pin', isWindowPinned);
  togglePinBtn.textContent = isWindowPinned ? '📌 Toggle Pin' : '📄 Just Paper';
});

再讓我們來稍微的優化一下樣式,運行 Electron 看看最終功能:

image

至此,功能已經全部完成

打包構建#

這裡我們使用 electron-builder 來進行打包,在 package.json 中配置一下即可:

"build": {
    "appId": "com.yourdomain.memomark",
    "mac": {
      "category": "public.app-category.productivity",
      "icon": "assets/MemoMark.icns" // 你的logo
    },
    "dmg": {
      "title": "MemoMark",
      "icon": "assets/MemoMark.icns",
      "window": {
        "width": 600,
        "height": 400
      }
    },

注意,Mac 端的 logo 格式為 icns,別弄錯了哦~

運行打包構建命令:

npm run dist

打包成功!安裝之後便可以在本地使用自己開發的 Electron 應用了~

總結和一些小遺憾#

在選擇用於構建桌面應用的框架時,不僅需要考慮其功能性,還需要考慮其性能、運行時大小、開發經驗等因素。以下是 Electron 和 Tauri 的詳細對比:

ElectronTauri
體積Electron 的最小可執行文件體積約為 50MB,這是由於它依賴於完整的 Chromium 和 Node.js 運行時。Tauri 的一個顯著優勢是其小巧的體積。一個基本的 Tauri 應用的體積在幾百 KB 到 1-2MB 之間。
速度Electron 的速度受到其大體積的影響,因為需要加載完整的 Chromium 和 Node.js 運行時。Tauri 由 Rust 編寫,因此運行速度快,啟動時間短。
安全性Electron 的安全性取決於開發者如何使用它。不當使用可能導致安全漏洞,例如在渲染器進程中直接使用 Node.js API。Tauri 的設計理念是安全優先,它採用了一種嚴格的安全模型,包括禁止直接從渲染器訪問 Node.js API。
社區Electron 由 GitHub 開發,擁有大量的用戶和成熟的社區。它有大量的文檔和教程。Tauri 是一個相對較新的項目,其社區正在快速發展,但目前仍不如 Electron 成熟。
兼容性Electron 支持 Windows、macOS 和 Linux。Tauri 也支持 Windows、macOS 和 Linux。
開發經驗Electron 支持 HTML、CSS 和 JavaScript,因此前端開發者可以很快上手。Tauri 允許使用任何可以編譯成靜態 HTML、CSS 和 JavaScript 的前端框架,因此它對前端開發者來說是非常靈活的。
內存使用Electron 的內存使用較高,因為每個 Electron 應用都需要運行自己的 Chromium 和 Node.js 實例。Tauri 的內存使用相對更低,因為它不依賴於重量級的運行時環境。

就我實現的這個支持 markdown 的便簽,大小便已經達到了 237mb(當然也可能是我沒有進行優化),如果用 Tauri 的話,大小或許會控制的更好,這也是這個項目最大的遺憾了

如果你對這個項目感興趣,或許你可以點進去看看https://github.com/isolcat/MemoMark,
如果能夠下載下來體驗一下,提 issues 或者 pr 就更好了,希望這款支持 markdown 的 Electron 便簽應用能夠幫助到你~

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。