Electron-vite【實戰】MD 編輯器 -- 系統菜單(含菜單封裝,新建文件,打開文件,打開文件夾,保存文件,退出系統)

最終效果

在這里插入圖片描述

整體架構

src/main/index.ts

import { createMenu } from './menu'

在 const mainWindow 后

  // 加載菜單createMenu(mainWindow)

src/main/menu.ts

import { BrowserWindow, Menu, MenuItem, MenuItemConstructorOptions, dialog, shell } from 'electron'
import fs from 'fs/promises'
import path from 'path'
import { FileItem } from '../types'
// 系統菜單
const createMenu = (mainWindow: BrowserWindow): void => {const menuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [{label: '文件',submenu: []}]const menu: Menu = Menu.buildFromTemplate(menuTemplate)Menu.setApplicationMenu(menu)
}

submenu 內添加自定義的菜單

src/types.ts

export interface FileItem {content: stringfileName: stringfilePath: stringeditable?: boolean
}

新建文件

在這里插入圖片描述

src/main/menu.ts

        {label: '新建',accelerator: 'CmdOrCtrl+N',click: async () => {const { canceled, filePath } = await dialog.showSaveDialog({filters: [{name: 'Markdown Files',extensions: ['md']}]})if (!canceled) {try {await fs.writeFile(filePath, '')mainWindow.webContents.send('open-file', {content: '',filePath: filePath,fileName: path.basename(filePath)})} catch (error) {console.error('創建文件時出錯:', error)}}}},

src/renderer/src/App.vue

  window.electron.ipcRenderer.on('open-file', (_, { content, fileName, filePath }) => {markdownContent.value = contentcurrentFilePath.value = filePathif (!isFileExists(filePath)) {fileList.value.unshift({content,fileName,filePath})}})

打開文件

在這里插入圖片描述

src/main/menu.ts

        {label: '打開文件',accelerator: 'CmdOrCtrl+O',click: async () => {const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, {filters: [{ name: 'Markdown Files', extensions: ['md', 'markdown'] }],properties: ['openFile']})if (!canceled) {const content = await fs.readFile(filePaths[0], 'utf-8')mainWindow.webContents.send('open-file', {content,filePath: filePaths[0],fileName: path.basename(filePaths[0])})}return null}},

src/renderer/src/App.vue

  window.electron.ipcRenderer.on('open-file', (_, { content, fileName, filePath }) => {markdownContent.value = contentcurrentFilePath.value = filePathif (!isFileExists(filePath)) {fileList.value.unshift({content,fileName,filePath})}})

打開文件夾

src/main/menu.ts

        {label: '打開文件夾',accelerator: 'CmdOrCtrl+K',click: async () => {const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, {properties: ['openDirectory']})if (!canceled) {const folderPath = filePaths[0]try {const files = await fs.readdir(folderPath)const mdFiles = files.filter((file) =>['.md', '.markdown'].includes(path.extname(file)))const fileList: FileItem[] = []for (const mdFile of mdFiles) {const filePath = path.join(folderPath, mdFile)const content = await fs.readFile(filePath, 'utf-8')fileList.push({content,filePath,fileName: mdFile})}mainWindow.webContents.send('open-dir', fileList)mainWindow.webContents.send('open-file', fileList[0])} catch (error) {console.error('讀取文件夾失敗:', error)}}return null}},

src/renderer/src/App.vue

  window.electron.ipcRenderer.on('open-dir', (_, newFileList) => {// 使用 splice 方法更新數組fileList.value.splice(0, fileList.value.length, ...newFileList)})
  window.electron.ipcRenderer.on('open-file', (_, { content, fileName, filePath }) => {markdownContent.value = contentcurrentFilePath.value = filePathif (!isFileExists(filePath)) {fileList.value.unshift({content,fileName,filePath})}})

保存

src/main/menu.ts

        {label: '保存',accelerator: 'CmdOrCtrl+S',click: () => {mainWindow.webContents.send('save-file')}},

src/renderer/src/App.vue

  window.electron.ipcRenderer.on('save-file', () => {const content = markdownContent.valueif (currentFilePath.value) {// 存在文件路徑時,保存文件const filePath = currentFilePath.value// 更新文件列表內容fileList.value.forEach((file) => {if (file.filePath === filePath) {file.content = content}})window.electron.ipcRenderer.send('save-file', { content, filePath })} else {// 無文件路徑時,新建文件window.electron.ipcRenderer.send('new-file', content)}})

src/main/ipc.ts

  // 處理新建文件請求ipcMain.on('new-file', async (_e, content) => {const { canceled, filePath } = await dialog.showSaveDialog({filters: [{name: 'Markdown Files',extensions: ['md']}]})if (!canceled) {try {await fs.writeFile(filePath, content)mainWindow.webContents.send('open-file', {content: content,filePath: filePath,fileName: path.basename(filePath)})} catch (error) {console.error('創建文件時出錯:', error)}}})// 處理保存文件請求ipcMain.on('save-file', async (_e, data) => {try {await fs.writeFile(data.filePath, data.content, 'utf-8')} catch (error) {console.error('保存文件失敗:', error)}})

ipc.ts 的架構

src/main/index.ts

import { setupIPC } from './ipc'
setupIPC(mainWindow)

src/main/ipc.ts

import { ipcMain, BrowserWindow, shell, dialog } from 'electron'
import fs from 'fs/promises'
import path from 'path'
import { createContextMenu } from './menu'
export function setupIPC(mainWindow: BrowserWindow): void {// IPC相關代碼
}

退出

src/main/menu.ts

        {label: '退出',role: 'quit'}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907521.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907521.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907521.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【第4章 圖像與視頻】4.5 操作圖像的像素

文章目錄 前言示例-獲取和修改圖像數據圖像數據的遍歷方式圖像濾鏡負片濾鏡黑白濾鏡浮雕濾鏡filter濾鏡屬性 前言 getImageData() 與 putImageData() 這兩個方法分別用來獲取圖像的像素信息,以及向圖像中插入像素。與此同時,如果有需要,也可…

【Docker 從入門到實戰全攻略(一):核心概念 + 命令詳解 + 部署案例】

1. 是什么 Docker 是一個用于開發、部署和運行應用程序的開源平臺,它使用 容器化技術 將應用及其依賴打包成獨立的容器,確保應用在不同環境中一致運行。 2. Docker與虛擬機 2.1 Docker(容器化) 容器化是一種輕量級的虛擬化技術…

Vue:axios(POST請求)

發送 POST 請求 基本用法 axios.post(/api/login, {username: lcyyyy,password: 123456 }) .then(response > {console.log(請求成功:, response.data); }) .catch(error > {console.error(請求失敗:, error); });在 Vue 組件中使用 export default {methods: {async …

一周學會Pandas2之Python數據處理與分析-數據重塑與透視-unstack() - 解堆 (行 -> 列)

鋒哥原創的Pandas2 Python數據處理與分析 視頻教程: 2025版 Pandas2 Python數據處理與分析 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili unstack() 是 pandas 中用于數據重塑的重要方法,它與 stack() 互為逆操作。unstack() 的主要功能是將行索…

基于大模型預測的FicatIII-IV期股骨頭壞死綜合治療研究報告

目錄 一、引言 1.1 研究背景與目的 1.2 國內外研究現狀 1.3 研究意義和創新點 二、FicatIII-IV 期股骨頭壞死概述 2.1 疾病定義與分期 2.2 病因與病理機制 2.3 臨床癥狀與診斷方法 三、大模型預測原理與方法 3.1 大模型簡介 3.2 數據收集與預處理 3.3 模型訓練與優…

C++?多態!!!

一、引言 眾所周知,C有三大特性,它們分別是封裝、繼承和多態,在之前的文章中已經詳細介紹過封裝和繼承了,今天我們將一起學習多態相關的知識,如果還想了解封裝、繼承相關的知識,可以跳轉到以下鏈接&#xf…

electron安裝報錯處理

electron安裝報錯 解決方法: 修改 C:\Users\用戶名.npmrc下配置文件 添加代碼 electron_mirrorhttps://cdn.npmmirror.com/binaries/electron/ electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron-builder-binaries/最后代碼 registryhtt…

Windows10下使用QEMU安裝Ubuntu20.04虛擬機,并啟用硬件加速

Windows10下使用QEMU安裝Ubuntu20.04虛擬機,并啟用硬件加速 作者將狼才鯨創建日期2025-05-30 CSDN閱讀地址:Windows10下使用QEMU安裝Ubuntu20.04虛擬機,并啟用硬件加速 本文檔源碼地址:Windows10下使用QEMU安裝Ubuntu20.04虛擬機…

頂刊SCS | 基于視覺語言大模型推理分割的建筑足跡尺度功能分類, 樣本數據和代碼已開源!

論文介紹 題目:Visual-language reasoning segmentation (LARSE) of function-level building footprint across Yangtze River Economic Belt of China 期刊:Sustainable cities and society(中科院一區TOP,IF10.5)…

【軟件】navicat 官方免費版

Navicat Premium Lite https://www.navicat.com.cn/download/navicat-premium-lite

每個路由器接口,都必須分配所屬網絡內的 IP 地址,用于轉發數據包

在IP網絡中,主機(Host)和路由器接口(Router Interface)都需要分配網絡地址(IP地址)。 1. 主機(Host)的IP地址分配 (1) 作用 主機的IP地址用于唯一標識該設備&#xff0…

鴻蒙OSUniApp頁面切換動效實戰:打造流暢精致的轉場體驗#三方框架 #Uniapp

UniApp頁面切換動效實戰:打造流暢精致的轉場體驗 引言 在移動應用開發中,頁面切換動效不僅能提升用戶體驗,還能傳達應用的品質感。隨著HarmonyOS的普及,用戶對應用的動效體驗要求越來越高。本文將深入探討如何在UniApp中實現流暢…

Tesseract OCR 安裝與中文+英文識別實現

一、下載 https://digi.bib.uni-mannheim.de/tesseract/ 下載,盡量選擇時間靠前的(識別更好些)。符合你的運行機(我的是windows64) 持續點擊下一步安裝,安裝你認可的路徑即可,沒必要配置環境變…

Visual Studio 2022 發布獨立的 exe 文件

我們在用 Visual Studio 2022 寫好一個 exe 程序之后,如果想把這個拿到其他地方運行,需要把 exe 所在的文件夾一起拿過去。 編譯出來的 exe 文件需要其他幾個文件一同放在同一目錄才能運行,原因在于默認情況下,Visual Studio 是把…

Kotlin-特殊類型

文章目錄 數據類型枚舉類型匿名類和伴生對象單例類伴生對象 數據類型 聲明一個數據類非常簡單: //在class前面添加data關鍵字表示為一個數據類 data class Student(var name: String, var age: Int)數據類聲明后,編譯器會根據主構造函數中聲明的所有屬性自動為其生成以下函數…

在線博客系統【測試報告】

🕒 一. 項目背景 由于紙質筆記容易丟失,攜帶不變,為了方便自己學習的過程中記錄筆記,特開發了這個博客系統。這個系統后端采用 SpringBoot MyBatis SpringMVC ;前端使用Html CSS JS;數據庫使用的是Mysq…

每日刷題c++

快速冪 #include <iostream> using namespace std; #define int long long int power(int a, int b, int p) {int ans 1;while (b){if (b % 2){ans * a;ans % p; // 隨時取模}a * a;a % p; // 隨時取模b / 2;}return ans; } signed main() {int a, b, p;cin >> a …

Python中的變量、賦值及函數的參數傳遞概要

Python中的變量、賦值及函數的參數傳遞概要 python中的變量、賦值 python中的變量不是盒子。 python中的變量無法用“變量是盒子”做解釋。圖說明了在 Python 中為什么不能使用盒子比喻&#xff0c;而便利貼則指出了變量的正確工作方式。 如果把變量想象為盒子&#xff0c;那…

KVM 安裝 Ubuntu 22

在 KVM 中安裝 Ubuntu 22 虛擬機。 首先創建硬盤文件 sudo qemu-img create -f qcow2 /app/vms/ubuntu22.qcow2 100G安裝Ubuntu 22 sudo virt-install \--name ubuntu22 \--ram 4096 \--vcpus 2 \--disk path/app/vms/ubuntu22.qcow2,formatqcow2 \--os-type linux \--os-va…

基于生產-消費模式,使用Channel進行文件傳輸(Tcp方式)

Client端&#xff1a; #region 多文件傳輸 public class FileMetadata {public string FileName { get; set; }public long FileSize { get; set; } }class Program {const int PORT 8888;const int BUFFER_SIZE 60 * 1024 * 1024;//15s-50 25s-64 33s-32 27s-50 31s-40 25…