源代码仓库:
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 函数
<Button
icon={<DatabaseOutlined />}
size="large"
style={{ marginLeft: 20 }}
onClick={setRepoPath}
>
Add Local Repository
</Button>
</div>
</div>
)}
</div>
)
}
export default App