源代码仓库:
Github仓库【electron_git】Commit :
bb40040
Github Desktop 页面分析
本节目标:
1、实现类似Github Desktop的「空仓库」提示页
2、添加本地仓库逻辑编写
从 Github Desktop 我们看到 他的 主要页面分为三个区域
- Head头部区域 (操作分支)
- Side侧边栏区域 (查看更新的文件)
- Main主区域 (查看 文件 Diff内容)
Tip:其实初始化的时候只有一个类似main的界面,这里因为我已经添加过store了,所以有head和side部分。
一、目录搭建及依赖安装
- Ant Design 官网
- Redux 官网
- react-router 官网
- localforage官网
# 安装依赖
pnpm install antd --save
pnpm install @reduxjs/toolkit react-redux
pnpm add -D sass-embedded
pnpm install react-router-dom# 简化持久化存储 根据 IndexedDB 和 WebSQL 支持进行降级策略
pnpm install localforage
主要文件
二、IPC 通信模块设计与实现
核心实现流程
1. IPC 模块注册机制
// ipc/index.js
import setupGitIPC from './git'
import setupChooseFileIPC from './operateTheFile'/*** 聚合所有 IPC 通信模块* 新增 IPC 模块需在此处引入并调用*/
export async function setupIPC() {setupGitIPC()setupChooseFileIPC()
}
// main/index.js
import { setupIPC } from '../ipc'app.whenReady().then(() => {setupIPC() // 注册所有 IPC 通信createWindow()// ...其他初始化逻辑
})
2. 文件选择器实现
// operateTheFile/index.js/*** 系统级文件夹选择对话框* @returns {Promise<string|null>} 选择的文件夹路径*/
const chooseFolder = async () => {const result = await dialog.showOpenDialog(mainWindow, {properties: ['openDirectory']})if (result.filePaths.length > 0) {return result.filePaths[0]}
}
const setupChooseFileIPC = () => {ipcMain.handle('chooseFolder', () => {return chooseFolder()})
}
3.预处理层暴露 API
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'// Custom APIs for renderer
const api = {/*** 打开文件夹选择对话框* @returns {Promise<string|null>}*/chooseFolder: () => {return ipcRenderer.invoke('chooseFolder')}
}
4. 渲染进程调用示例
在app.jsx
中我们点击button按钮时会调用window.api.chooseFolder
唤起原生文件选择器操作文件
function App() {const gitStroe = useSelector((state) => state.gitStore)const dispatch = useDispatch()const outlet = useRoutes(router)// 定义一个异步函数 setRepoPath,用于选择文件夹并设置仓库路径const setRepoPath = async () => {// 调用 window.api.chooseFolder() 弹出文件夹选择对话框,并等待用户选择文件夹const repoPath = await window.api.chooseFolder()// 检查 gitStroe.repoPaths 中是否已经包含选择的文件夹路径if (!gitStroe.repoPaths.some((item) => item.path === repoPath)) {// 如果不包含,则将选择的文件夹路径添加到 gitStroe.repoPaths 中,并更新仓库名称dispatch(setRepoPaths([...gitStroe.repoPaths, { path: repoPath, name: repoPath.split('/').pop() }]))// 设置当前仓库为选择的文件夹名称dispatch(setCurrentRepo(repoPath.split('/').pop()))}}return (<div className="app-container">......// 点击按钮触发 setRepoPath 函数<Buttonicon={<DatabaseOutlined />}size="large"style={{ marginLeft: 20 }}onClick={setRepoPath}>Add Local Repository</Button></div></div>)}</div>)
}export default App