从零构建桌面写作软件的书籍管理系统:Electron + Vue 3 实战指南

📚 从零构建桌面写作软件的书籍管理系统:Electron + Vue 3 实战指南

💡 本文深入探讨了基于 Electron + Vue 3 技术栈的桌面写作软件中书籍管理系统的设计与实现,涵盖了书籍的创建、编辑、删除等核心功能的完整技术方案,为开发者提供一套完整的书籍管理解决方案。

📋 目录

  • 项目背景
  • 技术架构概览
  • 书籍管理核心功能实现
  • 核心功能实现细节
  • 用户体验优化
  • 技术亮点总结
  • 扩展性考虑
  • 总结与展望

🎯 项目背景

51mazi 是一款专为小说创作者设计的桌面写作软件,其核心功能之一就是完善的书籍管理系统。作者需要一个直观、高效的书籍管理界面来组织和管理自己的创作项目,包括书籍的创建、编辑、删除以及元数据管理等功能。

📖 书籍管理界面

书籍管理

直观的书籍管理界面 - 支持创建、编辑、删除等操作

✨ 功能特性

  • 📝 书籍创建: 支持多种类型书籍创建
  • ✏️ 书籍编辑: 实时编辑书籍信息和元数据
  • 🗑️ 书籍删除: 安全删除确认机制
  • 📊 数据统计: 字数统计和更新记录
  • 🎨 界面美观: 书籍卡片式展示
  • 🔄 实时同步: 状态管理和数据同步

🏗️ 技术架构概览

核心技术栈

  • Electron 35.0.3: 跨平台桌面应用框架
  • Vue 3.5.13: 渐进式 JavaScript 框架
  • Element Plus 2.10.1: 企业级 UI 组件库
  • Pinia 3.0.1: Vue 3 官方推荐的状态管理库

系统架构设计

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   渲染进程      │    │   主进程        │    │   文件系统      │
│   (Vue 3)      │◄──►│   (Node.js)     │◄──►│   (本地存储)    │
└─────────────────┘    └─────────────────┘    └─────────────────┘

📁 项目目录结构

51mazi/
├── src/
│   ├── main/           # Electron 主进程
│   │   └── index.js    # 主进程入口文件
│   ├── preload/        # 预加载脚本
│   │   └── index.js    # IPC 通信接口
│   └── renderer/       # 渲染进程 (Vue 应用)
│       ├── src/
│       │   ├── components/    # 组件库
│       │   │   ├── Bookshelf.vue    # 书籍列表组件
│       │   │   └── Book.vue         # 书籍卡片组件
│       │   ├── views/         # 页面视图
│       │   ├── stores/        # 状态管理
│       │   │   └── index.js   # Pinia 状态管理
│       │   ├── service/       # 服务层
│       │   │   └── books.js   # 书籍相关 API
│       │   └── utils/         # 工具函数
│       └── assets/            # 静态资源

🔧 书籍管理核心功能实现

1. 📊 书籍数据结构设计

每本书籍包含以下核心信息:

const bookData = {id: 'unique_id',           // 唯一标识name: '书籍名称',           // 书名type: 'novel',             // 类型typeName: '小说',          // 类型名称targetCount: 100000,       // 目标字数intro: '书籍简介',         // 简介createdAt: '2024-01-01',  // 创建时间updatedAt: '2024-01-01',  // 更新时间totalWords: 50000          // 当前字数
}

💡 完整数据结构请查看: src/renderer/src/components/Bookshelf.vue

2. 🗂️ 主进程文件操作层

在主进程中实现文件系统操作,确保数据持久化:

// src/main/index.js
import { ipcMain } from 'electron'
import fs from 'fs'
import { join } from 'path'// 创建书籍
ipcMain.handle('create-book', async (event, bookInfo) => {const safeName = bookInfo.name.replace(/[\\/:*?"<>|]/g, '_')const booksDir = store.get('booksDir')const bookPath = join(booksDir, safeName)// 创建书籍目录结构if (!fs.existsSync(bookPath)) {fs.mkdirSync(bookPath)}// 写入元数据文件const meta = {...bookInfo,createdAt: new Date().toLocaleString(),updatedAt: new Date().toLocaleString()}fs.writeFileSync(join(bookPath, 'mazi.json'), JSON.stringify(meta, null, 2))// 创建默认目录结构const textPath = join(bookPath, '正文')const notesPath = join(bookPath, '笔记')fs.mkdirSync(textPath, { recursive: true })fs.mkdirSync(notesPath, { recursive: true })return true
})// 删除书籍
ipcMain.handle('delete-book', async (event, { name }) => {const booksDir = store.get('booksDir')const bookPath = join(booksDir, name)if (fs.existsSync(bookPath)) {fs.rmSync(bookPath, { recursive: true })return true}return false
})// 编辑书籍
ipcMain.handle('edit-book', async (event, bookInfo) => {const booksDir = store.get('booksDir')const bookPath = join(booksDir, bookInfo.name)if (fs.existsSync(bookPath)) {const metaPath = join(bookPath, 'mazi.json')const existingMeta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'))const mergedMeta = { ...existingMeta, ...bookInfo }fs.writeFileSync(metaPath, JSON.stringify(mergedMeta, null, 2))return true}return false
})

💡 完整主进程代码请查看: src/main/index.js

3. 🔌 渲染进程服务层

在渲染进程中封装 API 调用,提供统一的接口:

// src/renderer/src/service/books.js
export function createBook(bookInfo) {return window.electron.createBook(bookInfo)
}export function updateBook(bookInfo) {return window.electron.editBook(bookInfo)
}export async function deleteBook(name) {const dir = await getBookDir()return window.electron.deleteBook(dir, name)
}export async function readBooksDir() {const mainStore = useMainStore()const dir = await getBookDir()if (!dir) return []const books = await window.electron.readBooksDir(dir)mainStore.setBooks(books)return books
}

💡 完整服务层代码请查看: src/renderer/src/service/books.js

4. 🎨 用户界面组件设计

4.1 📚 书籍列表组件 (Bookshelf.vue)
<template><div class="bookshelf"><!-- 顶部操作栏 --><div class="top-bar"><el-button type="primary" @click="handleNewBook"><el-icon><Plus /></el-icon>新建书籍</el-button></div><!-- 书籍列表 --><div class="books-box"><Bookv-for="book in books":key="book.id":name="book.name":type="book.type":type-name="book.typeName":total-words="book.totalWords":updated-at="book.updatedAt"@on-open="onOpen(book)"@on-edit="onEdit(book)"@on-delete="onDelete(book)"/></div></div>
</template>

💡 完整书籍列表组件代码请查看: src/renderer/src/components/Bookshelf.vue

4.2 📖 书籍卡片组件 (Book.vue)
<template><div class="book" @click="emit('onOpen')" @contextmenu.prevent="showMenu($event)"><div class="spine"></div><div class="cover-bg"><div class="title-block"><div class="vertical-title">{{ name }}</div></div></div><div class="info"><div class="type">{{ typeName }}</div><div class="stats"><div class="word-count">字数:{{ totalWords }}</div><div class="update-time">更新:{{ updatedAt }}</div></div></div></div>
</template>

💡 完整书籍卡片组件代码请查看: src/renderer/src/components/Book.vue

5. 🗃️ 状态管理设计

使用 Pinia 进行全局状态管理:

// src/renderer/src/stores/index.js
import { defineStore } from 'pinia'
import { ref } from 'vue'export const useMainStore = defineStore('main', () => {const books = ref([])function setBooks(newBooks) {books.value = newBooks}function addBook(book) {books.value.push(book)}function removeBook(bookId) {const index = books.value.findIndex(book => book.id === bookId)if (index > -1) {books.value.splice(index, 1)}}return {books,setBooks,addBook,removeBook}
})

💡 完整状态管理代码请查看: src/renderer/src/stores/index.js

⚙️ 核心功能实现细节

1. 📝 书籍创建流程

async function handleConfirm() {formRef.value.validate(async (valid) => {if (valid) {// 校验同名书籍const exists = books.value.some((b) => b.name === form.value.name && (!isEdit.value || b.id !== editBookId.value))if (exists) {ElMessage.error('已存在同名书籍,不能重复创建!')return}const randomId = Date.now().toString() + Math.floor(Math.random() * 10000).toString()const bookData = {id: randomId,name: form.value.name,type: form.value.type,typeName: BOOK_TYPES.find((item) => item.value === form.value.type)?.label,targetCount: form.value.targetCount,intro: form.value.intro}await createBook(bookData)dialogVisible.value = falseawait readBooksDir()}})
}

💡 完整创建流程代码请查看: src/renderer/src/components/Bookshelf.vue

2. ✏️ 书籍编辑功能

function onEdit(book) {isEdit.value = trueeditBookId.value = book.iddialogVisible.value = trueform.value.name = book.nameform.value.type = book.typeform.value.targetCount = book.targetCountform.value.intro = book.intro
}

💡 完整编辑功能代码请查看: src/renderer/src/components/Bookshelf.vue

3. 🗑️ 书籍删除确认

async function onDelete(book) {try {await ElMessageBox.confirm(`确定要删除《${book.name}》吗?此操作不可恢复!`, '删除确认', {confirmButtonText: '删除',cancelButtonText: '取消',type: 'warning'})await deleteBook(book.name)ElMessage.success('删除成功')await readBooksDir()} catch (e) {// 用户取消删除console.log(e)}
}

💡 完整删除功能代码请查看: src/renderer/src/components/Bookshelf.vue

🎨 用户体验优化

1. 🖱️ 右键菜单支持

function showMenu(e) {menuX.value = e.clientXmenuY.value = e.clientYmenuVisible.value = truedocument.addEventListener('click', hideMenu)
}function hideMenu() {menuVisible.value = falsedocument.removeEventListener('click', hideMenu)
}

💡 完整右键菜单代码请查看: src/renderer/src/components/Book.vue

2. ✅ 表单验证

const rules = ref({name: [{ required: true, message: '请输入书籍名称', trigger: 'blur' }],type: [{ required: true, message: '请选择类型', trigger: 'blur' }],targetCount: [{ required: true, message: '请输入目标字数', trigger: 'blur' }],intro: [{ required: true, message: '请输入简介', trigger: 'blur' }]
})

💡 完整表单验证代码请查看: src/renderer/src/components/Bookshelf.vue

3. 💬 错误处理与用户反馈

// 创建成功提示
ElMessage.success('创建成功')// 删除确认
await ElMessageBox.confirm(`确定要删除《${book.name}》吗?此操作不可恢复!`, '删除确认', {confirmButtonText: '删除',cancelButtonText: '取消',type: 'warning'
})

💡 完整错误处理代码请查看: src/renderer/src/components/Bookshelf.vue

⚡ 技术亮点总结

1. 🔄 跨进程通信设计

  • 使用 Electron 的 IPC 机制实现主进程与渲染进程的安全通信
  • 通过 contextBridge 暴露安全的 API 接口

2. 🗂️ 文件系统管理

  • 自动创建标准化的书籍目录结构
  • 元数据 JSON 文件存储,便于扩展和维护
  • 文件名安全处理,避免特殊字符冲突

3. 🗃️ 状态管理优化

  • 使用 Pinia 实现响应式状态管理
  • 统一的数据流,确保 UI 与数据同步

4. 🎨 用户体验设计

  • 直观的书籍卡片展示
  • 右键菜单快速操作
  • 完善的表单验证和错误提示

🔮 扩展性考虑

1. 📚 书籍类型扩展

const BOOK_TYPES = [{ value: 'novel', label: '小说' },{ value: 'essay', label: '散文' },{ value: 'poetry', label: '诗歌' },{ value: 'script', label: '剧本' }
]

💡 完整书籍类型配置请查看: src/renderer/src/constants/config.js

2. 📊 元数据扩展

const bookMeta = {// 基础信息id: 'unique_id',name: '书籍名称',type: 'novel',// 扩展信息tags: ['标签1', '标签2'],status: 'writing', // writing, completed, pausedcoverImage: 'cover.jpg',wordCountGoal: 100000,// 统计信息currentWordCount: 50000,chaptersCount: 10,lastModified: '2024-01-01'
}

💡 完整元数据结构请查看: src/renderer/src/components/Bookshelf.vue

📝 总结与展望

通过 Electron + Vue 3 技术栈,我们成功构建了一个功能完善、用户体验优秀的书籍管理系统。该系统不仅满足了基本的 CRUD 操作需求,还在用户体验、数据安全、扩展性等方面进行了深度优化。

🎯 关键成功因素

  • 🏗️ 架构清晰: 主进程负责文件操作,渲染进程负责 UI 交互
  • 🔒 数据安全: 通过 IPC 机制确保跨进程通信的安全性
  • 🎨 用户体验: 直观的界面设计和流畅的操作体验
  • 🔧 可维护性: 模块化的代码结构和统一的状态管理

🚀 技术价值

  • 跨平台支持: 基于 Electron 实现 Windows、macOS、Linux 全平台支持
  • 高性能: 使用 Vue 3 的 Composition API 和 Pinia 状态管理
  • 可扩展: 模块化的组件设计和清晰的代码结构
  • 用户友好: 完善的错误处理和用户反馈机制

这个书籍管理系统为整个写作软件奠定了坚实的基础,为后续的功能扩展提供了良好的架构支持。


📚 相关链接

  • 项目地址: GitHub - 51mazi,给个 Star 哦~
  • Electron 官方文档: Electron Documentation
  • Vue 3 官方文档: Vue 3 Documentation
  • Pinia 状态管理: Pinia Documentation

🏷️ 标签

#Electron #Vue3 #书籍管理 #桌面应用 #前端开发 #状态管理 #用户体验


💡 如果这篇文章对你有帮助,请给个 ⭐️ 支持一下!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92376.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025华数杯数学建模A题【 多孔膜光反射性能的优化与控制】原创论文讲解(含完整python代码)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2025华数杯数学建模A题【 多孔膜光反射性能的优化与控制】完整的成品论文。本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。A题论…

网络相关(AI回答)

网管交换机都支持带tag的以太帧吗DeepSeek-R1 回答完成深度思考完成 用时24秒&#xff0c;搜索全网20篇资料是的&#xff0c;所有网管交换机都支持处理和转发带Tag&#xff08;802.1Q VLAN标签&#xff09;的以太网帧&#xff0c;这是其核心功能之一。以下是关键要点&#xff1…

每日五个pyecharts可视化图表-bars(5)

探索pyecharts库中条形图的高级用法与定制技巧&#xff0c;打造精美数据可视化图表 在数据可视化中&#xff0c;条形图是最常用的图表类型之一。它能够清晰地展示不同类别的数据对比&#xff0c;帮助我们快速理解数据特征。本文将为您介绍pyecharts库中条形图的5种高级用法&…

分布式版本控制工具Git

一.开发中为什么需要Git因为在多人开发中Git可以管理代码&#xff0c;而且每个人都可以从库里面下载代码进行修改&#xff0c;每个人上传和修改Git都会有记录&#xff0c;如果出现大错误&#xff0c;还可以回退到正常版本。二.Git原理我们首先从代码库(Remote)下载代码到工作区…

OpenAI重磅开源GPT-oss:首款支持商用的AI Agent专属模型

今日凌晨&#xff0c;OpenAI宣布开源两款全新大模型——GPT-oss-120B&#xff08;1168亿参数&#xff09;与GPT-oss-20B&#xff08;209亿参数&#xff09;&#xff0c;成为全球首个支持商业化应用的开放权重推理模型。该模型专为AI智能体&#xff08;Agent&#xff09;设计&am…

【STM32】GPIO的输入输出

GPIO是通用的输入输出接口&#xff0c;可配置8种输入模式&#xff0c;输出模式下可控制端口输出高低电平&#xff0c;用于点亮LED、控制蜂鸣器、模拟通信协议等&#xff1b;输入模式下可以读取端口的高低电平或者电压&#xff0c;用于读取按键、外接模块的电平信号、ADC的电压采…

5分钟了解OpenCV

在数字化时代&#xff0c;图像和视频已经成为信息传递的核心载体。从手机拍照的美颜功能到自动驾驶的路况识别&#xff0c;从医学影像分析到安防监控系统&#xff0c;视觉技术正深刻改变着我们的生活。而在这背后&#xff0c;OpenCV 作为一款强大的开源计算机视觉库&#xff0c…

Oracle 关闭 impdp任务

Oracle 关闭 impdp任务 执行 impdp system/123456 attachSYS_EXPORT_TABLE_01 执行 stop_jobimmediate

数据结构——链表2

1.2 实现单链表 在上一篇文章中&#xff0c;单链表的实现只有一少部分&#xff0c;这一篇接着来了解单链表剩下的接口实现。 SList.h#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h>//定义单链表就是定义节点&#xff0c;因为单链表…

Windows和Linux应急响应以及IP封堵

目录 1、Windows入侵排查思路 1.1 检查系统账号安全 1.2 检查异常端口、进程 1.3 检查启动项、计划任务、服务 1.4 检查系统相关信息 1.5 自动化查杀 1.6 日志分析 系统日志分析 Web 访问日志 2、Linux 入侵排查思路 2.1 账号安全 2.1.1、基本使用 2.1.2、入侵排查…

MIT成果登上Nature!液态神经网络YYDS

2025深度学习发论文&模型涨点之——液态神经网络液态神经网络&#xff08;Liquid Neural Networks&#xff0c;LNN&#xff09;是一种受生物神经系统启发的连续时间递归神经网络&#xff08;RNN&#xff09;&#xff0c;其核心创新在于将静态神经网络转化为由微分方程驱动的…

AI 对话高效输入指令攻略(四):AI+Apache ECharts:生成各种专业图表

- **AI与数据可视化的革命性结合**:介绍AI如何降低数据可视化门槛,提升效率。 - **Apache ECharts:专业可视化的利器**:使用表格对比展示ECharts的特点、优势和适用场景。 - **四步实现AI驱动图表生成**:通过分步指南讲解从环境准备到图表优化的全流程,包含多个代码示例及…

vue2 基础学习 day04 (结构/样式/逻辑、组件通信、进阶语法)下

一、非父子通信-event bus 事件总线1.作用非父子组件之间&#xff0c;进行简易消息传递。(复杂场景→ Vuex)2.步骤创建一个都能访问的事件总线 &#xff08;空Vue实例&#xff09;import Vue from vue const Bus new Vue() export default BusA组件&#xff08;接受方&#xf…

ubuntu 20.04 C和C++的标准头文件都放在哪个目录?

在 Ubuntu 20.04 中&#xff0c;C 和 C 标准头文件的存放目录主要由编译器&#xff08;如 GCC&#xff09;的安装路径决定&#xff0c;通常分为以下两类&#xff1a;​1. C 标准头文件​C 语言的标准头文件&#xff08;如 <stdio.h>、<stdlib.h> 等&#xff09;默认…

change和watch

是的&#xff0c;你理解得很对&#xff01; change 与 v-model 的结合&#xff1a;change 事件通常用于监听 表单元素的变化&#xff0c;但它并不一定意味着值发生了变化。它主要是当 用户与输入框交互时&#xff08;如点击选项、选择文本框内容、提交表单等&#xff09;触发的…

分布式微服务--GateWay(1)

一、什么是微服务网关&#xff08;API Gateway&#xff09; 定义&#xff1a;微服务网关是整个系统请求的统一入口&#xff0c;负责请求转发、过滤处理、安全校验等。 作用&#xff1a; 请求路由 日志记录 权限控制 参数校验 解决跨域问题 黑白名单控制 限流、熔断、降级…

大文件断点续传(vue+springboot+mysql)

断点续传vue前端代码后端代码controller 层service层持久层主表&#xff0c;初始化单次上传文件表&#xff0c;单次上传所有的文件记录文件分块表科普信息参考其他博主 流程图 vue前端代码 这里是只做了demo示例&#xff0c;主线测试没什么问题&#xff0c;前端同学可参考修…

Nodejs》》MySql

Node.js 操作MySQL数据库 文档 # 项目要先安装mysql包npm i mysqlxx // 安装指定版本npm i mysql // 默认安装最新版本 # 连接 mysq// 使用连接池连接const mysql require(mysql)# 建立连接const db mysql.createPool({host:, // 数据库的IP地址user:ro…

金仓数据库常见问题(持续更新)

目录 1.查看大小是否敏感写参数&#xff0c;提示&#xff1a;未认可的配置参数 "case_sensitive" 2.sys_backup.sh init时提示can not connect the primary node 3.设置逻辑备份运行脚本时提示错误are not allowed to use this program (crontab) 4.修改表字段类…

Docker Buildx最佳实践:多架构镜像构建指南

文章目录为什么需要 Docker Buildx安装与启用 Docker Buildx创建多架构构建器实例构建多架构镜像优化构建性能调试多架构构建实战案例&#xff1a;构建 Go 应用多架构镜像总结Docker Buildx 是 Docker 官方推出的扩展工具&#xff0c;用于支持多平台镜像构建&#xff0c;简化跨…