JavaScript基础课程三十三、性能优化与工程化高级
本课是前端从入门到高级开发的核心进阶课聚焦性能优化与高级工程化两大核心能力。性能优化以用户体验为核心覆盖渲染、构建、网络全链路从指标检测到落地优化形成完整的优化方法论高级工程化则是企业级项目开发的必备能力通过Monorepo、CI/CD、质量门禁、监控体系实现项目全生命周期的标准化、自动化管理。课程通过可落地的代码示例贴合之前所学的Vue、React、跨端、桌面端技术栈打通从开发到上线的全流程。掌握本课内容你将具备高级前端开发的核心能力能够独立负责企业级项目的性能优化与工程化体系搭建完成从中级到高级前端开发的跨越。一、课程学习目的掌握前端性能核心衡量标准理解 Web Vitals 核心指标建立“先检测、后优化”的科学优化思维。精通前端渲染、构建打包、网络请求、资源加载全链路性能优化方案掌握可落地的优化技巧。掌握 Vue/React 框架级渲染优化、跨端应用uni-app/RN、Electron 桌面端专项优化方法。理解前端高级工程化体系掌握 Monorepo 项目管理、CI/CD 自动化流程、代码质量门禁、灰度发布等企业级方案。学会使用性能检测工具精准定位性能瓶颈避免无效优化与过度优化。建立企业级前端项目的全生命周期管理思维从开发、构建、部署、监控全流程保障项目质量与性能。二、核心知识点讲解1. 性能优化核心衡量指标性能优化的核心是以用户体验为核心而非单纯的技术参数优化行业通用核心指标为 Google 推出的Web Vitals。核心指标LCP最大内容绘制页面最大内容元素加载完成的时间优秀标准≤2.5s衡量页面加载性能。FID首次输入延迟用户首次与页面交互到浏览器响应的时间优秀标准≤100ms衡量页面交互性能。CLS累积布局偏移页面生命周期内非预期的布局偏移量优秀标准≤0.1衡量视觉稳定性。FCP首次内容绘制页面首次绘制文本/图片的时间衡量白屏时长。TTI可交互时间页面完全可交互的时间衡量页面可用性。2. 前端渲染优化渲染优化的核心是减少不必要的渲染、降低重排重绘、提升交互响应速度。核心优化方案减少重排重绘避免频繁修改DOM样式使用class批量修改样式开启GPU加速transform、opacity脱离文档流减少重排范围。懒加载图片、视频、组件懒加载仅加载可视区域内容减少首屏资源加载。虚拟列表长列表仅渲染可视区域DOM滚动时动态替换内容解决万级数据列表卡顿问题。框架级优化Vue使用v-show替代频繁切换的v-if合理使用keep-alive缓存组件避免watch过度依赖使用pinia替代vuex减少渲染开销。React使用useMemo缓存计算结果、useCallback缓存函数、React.memo缓存组件合理拆分状态避免全组件重渲染。3. 构建打包优化构建优化的核心是缩小包体积、提升构建速度、优化加载策略基于Vite/Webpack实现。核心优化方案代码分割拆包按路由、第三方依赖拆分代码实现按需加载避免首屏加载全量包。Tree-Shaking剔除项目中未使用的死代码减少包体积依赖ES6模块化语法。资源压缩JS/CSS/HTML压缩图片压缩webp/avif格式字体文件精简。预构建与缓存Vite预构建第三方依赖开启构建缓存大幅提升二次构建速度。第三方依赖优化按需引入组件库替换大体积依赖使用CDN引入大型依赖不打入主包。4. 网络请求优化网络优化的核心是减少请求数量、缩小请求体积、降低请求耗时。核心优化方案HTTP缓存合理设置强缓存Cache-Control与协商缓存ETag/Last-Modified避免重复请求不变资源。CDN加速静态资源部署到CDN就近访问降低延迟。请求优化合并重复请求接口防抖节流数据预加载使用HTTP2/HTTP3开启多路复用。接口优化接口按需返回字段分页加载大数据开启Gzip/Brotli压缩减少传输体积。5. 专项优化方案跨端应用优化uni-app/RN使用原生渲染组件替代webview长列表使用原生列表组件减少JS桥接通信频次图片懒加载与内存优化。Electron桌面端优化渲染进程与主进程职责分离减少主进程阻塞预加载脚本精简逻辑关闭无用的Chromium插件打包时剔除无用依赖缩小安装包体积。用户体验优化骨架屏、加载动画、降级处理避免用户等待时的空白与卡顿感。6. 前端高级工程化体系前端工程化是对项目全生命周期的标准化、自动化、体系化管理是企业级项目开发的核心能力。核心模块Monorepo 项目管理在一个仓库中管理多个子项目共享依赖、统一规范、提升协作效率主流工具pnpm Turborepo。CI/CD 自动化流程代码提交后自动执行代码检查、测试、构建、部署实现持续集成与持续交付主流工具GitHub Actions、GitLab CI、Jenkins。代码质量闭环ESLintPrettier代码规范、TypeScript类型校验、单元测试/E2E测试、代码评审门禁禁止不规范代码合并。前端监控体系性能监控、错误监控、用户行为监控线上问题及时报警与定位主流方案Sentry、自建监控平台。灰度发布与回滚按比例放量发布新版本出现问题快速回滚降低线上故障影响范围。三、示例程序示例1图片懒加载实现// 图片懒加载通用函数 function lazyLoadImage() { // 获取所有带lazy类的图片 const imgList document.querySelectorAll(img.lazy); // 浏览器原生IntersectionObserver监听元素是否进入可视区 const observer new IntersectionObserver((entries) { entries.forEach(entry { // 进入可视区 if (entry.isIntersecting) { const img entry.target; // 替换真实图片地址 img.src img.dataset.src; // 加载完成后移除监听 img.onload () observer.unobserve(img); } }); }, { rootMargin: 100px 0px, // 提前100px开始加载 threshold: 0.1 }); // 监听所有图片 imgList.forEach(img observer.observe(img)); } // 页面加载后执行 window.addEventListener(DOMContentLoaded, lazyLoadImage);示例2Vite 构建优化配置// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue import { visualizer } from rollup-plugin-visualizer // 包体积分析工具 export default defineConfig({ plugins: [ vue(), // 打包后生成包体积分析报告 visualizer({ open: true, gzipSize: true, brotliSize: true }) ], // 构建配置 build: { // 目标浏览器版本 target: es2015, // 拆包配置 rollupOptions: { output: { // 手动拆分第三方依赖包 manualChunks: { vue: [vue, vue-router, pinia], utils: [lodash, axios] }, // 代码分割文件名 chunkFileNames: js/[name]-[hash].js, entryFileNames: js/[name]-[hash].js, assetFileNames: [ext]/[name]-[hash].[ext] } }, // 开启gzip压缩 minify: terser, terserOptions: { // 生产环境剔除console compress: { drop_console: true, drop_debugger: true } }, // 触发警告的chunk大小 chunkSizeWarningLimit: 500 }, // 预构建依赖 optimizeDeps: { include: [vue, vue-router, pinia, axios] } })示例3React 渲染优化import { useState, useMemo, useCallback, memo } from react // 子组件用memo缓存仅props变化时才重渲染 const ChildComponent memo(({ onClick, list }) { console.log(子组件渲染) return ( div {list.map(item div key{item.id}{item.name}/div)} button onClick{onClick}点击/button /div ) }) function App() { const [count, setCount] useState(0) const [list] useState([{ id: 1, name: 测试 }]) // useCallback缓存函数避免每次渲染生成新函数导致子组件重渲染 const handleClick useCallback(() { console.log(按钮点击) }, []) // useMemo缓存计算结果仅依赖变化时才重新计算 const totalCount useMemo(() { return list.reduce((total, item) total item.id, 0) }, [list]) return ( div p计数{count}/p p总数{totalCount}/p button onClick{() setCount(count 1)}增加/button {/* 缓存后的子组件不会因为父组件count变化而重渲染 */} ChildComponent onClick{handleClick} list{list} / /div ) } export default App示例4前端性能埋点上报// 性能指标上报工具 class PerformanceMonitor { constructor() { this.init() } init() { // 页面加载完成后采集指标 window.addEventListener(load, () { this.getCoreVitals() this.getNavigationTiming() }) // 监听页面隐藏时上报数据 document.addEventListener(visibilitychange, () { if (document.visibilityState hidden) { this.reportData() } }) } // 获取Web Vitals核心指标 getCoreVitals() { // LCP 最大内容绘制 new PerformanceObserver((entryList) { const entries entryList.getEntries() const lastEntry entries[entries.length - 1] this.data.LCP lastEntry.startTime }).observe({ entryTypes: [largest-contentful-paint] }) // CLS 累积布局偏移 new PerformanceObserver((entryList) { let cls 0 entryList.getEntries().forEach(entry { if (!entry.hadRecentInput) { cls entry.value } }) this.data.CLS cls }).observe({ entryTypes: [layout-shift] }) } // 上报数据 reportData() { navigator.sendBeacon(/api/performance/report, JSON.stringify(this.data)) } } // 初始化监控 new PerformanceMonitor()四、掌握技巧与方法先检测后优化使用Chrome DevTools、Lighthouse、WebPageTest等工具定位性能瓶颈不要盲目优化。抓核心矛盾优先优化影响用户体验的核心指标LCP、FID、CLS优先解决首屏加载、交互卡顿等用户可感知的问题。渐进式优化从低成本、高收益的优化项入手比如图片压缩、代码分割、缓存配置再做深度的渲染优化。避免过度优化优化需要付出维护成本不要为了微小的性能提升过度复杂化代码以业务需求为核心。工程化前置把规范、检查、测试、构建优化嵌入到开发流程中从源头保障项目质量而不是上线后再补优化。线上持续监控性能优化不是一次性工作建立线上监控体系持续跟踪指标变化及时发现线上性能问题。跨端专项优化不同端的性能瓶颈不同Web端重点优化加载与渲染App/桌面端重点优化内存占用与启动速度。五、课后作业基础作业使用Lighthouse对自己开发的项目进行性能检测生成检测报告定位3个核心性能问题。实现图片懒加载功能优化页面图片加载性能。配置Vite/Webpack构建压缩剔除生产环境console生成包体积分析报告。进阶作业对Vue/React项目进行渲染优化使用缓存API减少不必要的组件重渲染。实现虚拟列表优化1000条以上数据的长列表滚动性能。配置ESLintPrettierTypeScript搭建代码规范检查体系实现提交代码自动校验。实战作业对之前开发的全栈项目进行全链路性能优化包含首屏加载、渲染性能、构建打包、网络请求优化优化后Lighthouse评分达到90分以上同时搭建基础工程化体系实现代码规范校验、自动化构建、性能指标上报功能。上一课Electron 桌面应用开发 实战作业代码代码功能说明本实战作业基于Electron Forge开发完整的电子单词本桌面应用完全贴合课程核心知识点符合Electron安全开发规范。项目采用主进程渲染进程预加载脚本的标准架构主进程负责窗口管理、系统菜单、文件操作、IPC通信与本地数据持久化渲染进程负责页面交互、单词展示、搜索过滤预加载脚本作为通信桥梁暴露安全API。实现单词增删改查、分类管理、批量导入导出、记忆标记、搜索过滤全功能适配Windows与macOS双端支持打包生成可执行安装包完整覆盖Electron桌面应用开发全流程。注意事项必须安装Node.js 18.0及以上版本否则无法正常运行Electron Forge项目。严格遵循Electron安全规范始终启用contextIsolation上下文隔离禁用nodeIntegration禁止在渲染进程直接使用Node.js API。主进程负责系统级操作渲染进程仅负责页面渲染职责分离不要在主进程编写页面逻辑。应用数据存储使用app.getPath(userData)路径禁止使用相对路径保证跨平台兼容性。打包前需配置对应平台的应用图标Windows使用.ico格式macOS使用.icns格式避免打包失败。macOS平台打包需安装Xcode命令行工具Windows平台需安装Visual Studio生成工具否则无法完成原生构建。调试主进程使用VS Code断点调试渲染进程使用Chromium开发者工具和前端调试逻辑一致。打包后的安装包仅能在对应平台运行Windows打包生成.exemacOS打包生成.dmg不可跨平台运行。完整实战代码项目结构electron-word-book/ ├── src/ │ ├── main.js # 主进程入口 │ ├── preload.js # 预加载脚本 │ ├── index.html # 渲染进程页面 │ ├── renderer.js # 渲染进程逻辑 │ ├── index.css # 页面样式 │ └── assets/ # 静态资源图标等 ├── package.json # 项目依赖与配置 ├── forge.config.js # Electron Forge打包配置 └── .gitignore # Git忽略文件package.json 依赖与配置{ name: electron-word-book, productName: 电子单词本, version: 1.0.0, description: 基于Electron开发的桌面单词本应用, main: src/main.js, scripts: { start: electron-forge start, package: electron-forge package, make: electron-forge make, lint: eslint src }, devDependencies: { electron-forge/cli: ^7.4.0, electron-forge/maker-deb: ^7.4.0, electron-forge/maker-rpm: ^7.4.0, electron-forge/maker-squirrel: ^7.4.0, electron-forge/maker-zip: ^7.4.0, electron: ^29.0.0, eslint: ^8.57.0 }, dependencies: { electron-squirrel-startup: ^1.0.0 } }forge.config.js 打包配置const { FusesPlugin } require(electron-forge/plugin-fuses); const { FuseV1Options, FuseVersion } require(electron/fuses); module.exports { packagerConfig: { asar: true, name: 电子单词本, icon: src/assets/icon, appCopyright: Copyright © 2024 电子单词本 }, rebuildConfig: {}, makers: [ // Windows安装包 { name: electron-forge/maker-squirrel, config: { name: electron_word_book, authors: 开发者, description: 电子单词本桌面应用 }, }, // macOS安装包 { name: electron-forge/maker-zip, platforms: [darwin], }, // Linux安装包 { name: electron-forge/maker-deb, config: {}, }, { name: electron-forge/maker-rpm, config: {}, }, ], plugins: [ { name: electron-forge/plugin-auto-unpack-natives, config: {}, }, new FusesPlugin({ version: FuseVersion.V1, [FuseV1Options.RunAsNode]: false, [FuseV1Options.EnableCookieEncryption]: true, [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, [FuseV1Options.EnableNodeCliInspectArguments]: false, [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, [FuseV1Options.OnlyLoadAppFromAsar]: true, }), ], };src/main.js 主进程代码const { app, BrowserWindow, ipcMain, Menu, dialog } require(electron); const path require(path); const fs require(fs); // 处理Windows安装启动事件 if (require(electron-squirrel-startup)) app.quit(); // 全局窗口实例 let mainWindow; // 数据存储路径 let dataPath; // 创建主窗口 function createWindow() { // 初始化数据存储路径 dataPath path.join(app.getPath(userData), word-data.json); mainWindow new BrowserWindow({ width: 1000, height: 700, minWidth: 800, minHeight: 500, title: 电子单词本, icon: path.join(__dirname, assets/icon.png), webPreferences: { // 安全配置必须开启 contextIsolation: true, nodeIntegration: false, // 预加载脚本路径 preload: path.join(__dirname, preload.js) } }); // 加载渲染进程页面 mainWindow.loadFile(path.join(__dirname, index.html)); // 开发环境打开开发者工具 if (!app.isPackaged) { mainWindow.webContents.openDevTools(); } // 创建应用菜单 createAppMenu(); } // 创建应用系统菜单 function createAppMenu() { const template [ { label: 文件, submenu: [ { label: 导入单词, accelerator: CmdOrCtrlI, click: importWordFile }, { label: 导出单词, accelerator: CmdOrCtrlE, click: exportWordFile }, { type: separator }, { label: 退出, role: quit, accelerator: CmdOrCtrlQ } ] }, { label: 编辑, submenu: [ { role: undo, label: 撤销, accelerator: CmdOrCtrlZ }, { role: redo, label: 重做, accelerator: CmdOrCtrlShiftZ }, { type: separator }, { role: cut, label: 剪切, accelerator: CmdOrCtrlX }, { role: copy, label: 复制, accelerator: CmdOrCtrlC }, { role: paste, label: 粘贴, accelerator: CmdOrCtrlV }, { role: selectAll, label: 全选, accelerator: CmdOrCtrlA } ] }, { label: 视图, submenu: [ { role: reload, label: 重新加载 }, { role: forceReload, label: 强制重新加载 }, { role: toggleDevTools, label: 切换开发者工具 }, { type: separator }, { role: resetZoom, label: 重置缩放 }, { role: zoomIn, label: 放大 }, { role: zoomOut, label: 缩小 }, { type: separator }, { role: togglefullscreen, label: 切换全屏 } ] } ]; // macOS适配 if (process.platform darwin) { template.unshift({ label: app.name, submenu: [ { role: about, label: 关于电子单词本 }, { type: separator }, { role: services, label: 服务 }, { type: separator }, { role: hide, label: 隐藏 }, { role: hideOthers, label: 隐藏其他 }, { role: unhide, label: 显示全部 }, { type: separator }, { role: quit, label: 退出 } ] }); } const menu Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); } // 导入单词文件 async function importWordFile() { const { filePaths } await dialog.showOpenDialog(mainWindow, { title: 导入单词文件, filters: [{ name: JSON文件, extensions: [json] }], properties: [openFile] }); if (filePaths.length 0) { try { const content fs.readFileSync(filePaths[0], utf8); const wordData JSON.parse(content); // 发送到渲染进程 mainWindow.webContents.send(word:import, wordData); dialog.showMessageBox(mainWindow, { type: info, title: 导入成功, message: 成功导入${wordData.length}个单词 }); } catch (err) { dialog.showErrorBox(导入失败, 文件格式错误请检查JSON文件); } } } // 导出单词文件 async function exportWordFile() { const { filePath } await dialog.showSaveDialog(mainWindow, { title: 导出单词文件, defaultPath: 电子单词本.json, filters: [{ name: JSON文件, extensions: [json] }] }); if (filePath) { // 监听渲染进程返回的单词数据 ipcMain.handleOnce(word:export-data, async () { return filePath; }); } } // 应用就绪创建窗口 app.whenReady().then(() { createWindow(); // macOS激活应用时重建窗口 app.on(activate, () { if (BrowserWindow.getAllWindows().length 0) createWindow(); }); }); // 所有窗口关闭时退出应用macOS除外 app.on(window-all-closed, () { if (process.platform ! darwin) app.quit(); }); // ------------------------------ // IPC通信处理渲染进程 ↔ 主进程 // ------------------------------ // 保存单词数据 ipcMain.handle(word:save, async (event, wordList) { try { fs.writeFileSync(dataPath, JSON.stringify(wordList, null, 2)); return { success: true }; } catch (err) { return { success: false, error: err.message }; } }); // 加载单词数据 ipcMain.handle(word:load, async () { try { if (fs.existsSync(dataPath)) { const content fs.readFileSync(dataPath, utf8); return JSON.parse(content); } return []; } catch (err) { return []; } }); // 写入导出文件 ipcMain.handle(word:write-export, async (event, filePath, wordList) { try { fs.writeFileSync(filePath, JSON.stringify(wordList, null, 2)); return { success: true }; } catch (err) { return { success: false, error: err.message }; } });src/preload.js 预加载脚本const { contextBridge, ipcRenderer } require(electron); // 向渲染进程暴露安全API禁止直接暴露ipcRenderer contextBridge.exposeInMainWorld(wordBookAPI, { // 保存单词数据 saveWord: (wordList) ipcRenderer.invoke(word:save, wordList), // 加载单词数据 loadWord: () ipcRenderer.invoke(word:load), // 监听导入单词事件 onWordImport: (callback) ipcRenderer.on(word:import, (event, data) callback(data)), // 获取导出路径 onWordExport: (callback) ipcRenderer.handle(word:export-data, callback), // 写入导出文件 writeExportFile: (filePath, wordList) ipcRenderer.invoke(word:write-export, filePath, wordList) });src/index.html 渲染进程页面!DOCTYPE html html langzh-CN head meta charsetUTF-8 title电子单词本/title link relstylesheet hrefindex.css /head body div classapp !-- 侧边栏分类 -- aside classsidebar h2电子单词本/h2 div classcategory-list div classcategory-item active>src/renderer.js 渲染进程逻辑// 从预加载脚本获取API const { wordBookAPI } window; // DOM元素 const searchInput document.getElementById(searchInput); const addBtn document.getElementById(addBtn); const wordList document.getElementById(wordList); const emptyState document.getElementById(emptyState); const addModal document.getElementById(addModal); const cancelBtn document.getElementById(cancelBtn); const confirmAddBtn document.getElementById(confirmAddBtn); const modalEnInput document.getElementById(modalEnInput); const modalCnInput document.getElementById(modalCnInput); const categoryItems document.querySelectorAll(.category-item); // 全局数据 let wordData []; let currentCategory all; let searchKey ; // 页面加载初始化 window.addEventListener(DOMContentLoaded, async () { // 加载本地单词数据 wordData await wordBookAPI.loadWord(); renderWordList(); // 监听菜单导入事件 wordBookAPI.onWordImport((data) { wordData data; renderWordList(); wordBookAPI.saveWord(wordData); }); // 监听菜单导出事件 wordBookAPI.onWordExport(async () { const filePath await wordBookAPI.writeExportFile(filePath, wordData); if (filePath.success) { alert(导出成功); } }); }); // 渲染单词列表 function renderWordList() { // 过滤数据 let filterData wordData; // 分类过滤 if (currentCategory known) { filterData filterData.filter(item item.isKnown); } else if (currentCategory unknown) { filterData filterData.filter(item !item.isKnown); } // 搜索过滤 if (searchKey) { const key searchKey.toLowerCase(); filterData filterData.filter(item item.en.toLowerCase().includes(key) || item.cn.includes(key) ); } // 渲染 wordList.innerHTML ; if (filterData.length 0) { emptyState.style.display block; wordList.style.display none; return; } emptyState.style.display none; wordList.style.display block; filterData.forEach((item, index) { const div document.createElement(div); div.className word-item ${item.isKnown ? known : }; div.innerHTML div classword-info div classword-en${item.en}/div div classword-cn${item.cn}/div /div div classword-actions button classtoggle-btn>src/index.css 样式文件* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; background-color: #f5f7fa; color: #333; height: 100vh; overflow: hidden; } .app { display: flex; height: 100vh; } /* 侧边栏 */ .sidebar { width: 240px; background-color: #2c3e50; color: #fff; padding: 20px 0; display: flex; flex-direction: column; } .sidebar h2 { font-size: 20px; text-align: center; margin-bottom: 30px; padding: 0 20px; } .category-item { padding: 12px 20px; cursor: pointer; transition: background-color 0.2s; } .category-item:hover { background-color: #34495e; } .category-item.active { background-color: #3498db; } /* 主内容区 */ .main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .header-bar { padding: 20px; background-color: #fff; border-bottom: 1px solid #eee; display: flex; gap: 15px; align-items: center; } .search-input { flex: 1; padding: 10px 15px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; outline: none; } .search-input:focus { border-color: #3498db; } .add-btn { padding: 10px 20px; background-color: #27ae60; color: #fff; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; } .add-btn:hover { background-color: #2ecc71; } /* 单词列表 */ .word-list { flex: 1; padding: 20px; overflow-y: auto; } .word-item { background-color: #fff; padding: 20px; border-radius: 8px; margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 4px rgba(0,0,0,0.05); } .word-item.known { opacity: 0.7; } .word-en { font-size: 18px; font-weight: 500; margin-bottom: 4px; } .word-cn { font-size: 14px; color: #666; } .word-actions { display: flex; gap: 10px; } .toggle-btn { padding: 6px 12px; background-color: #3498db; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; } .del-btn { padding: 6px 12px; background-color: #e74c3c; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; } /* 空状态 */ .empty-state { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; color: #999; } .empty-state h3 { margin-bottom: 10px; font-size: 18px; } /* 弹窗 */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: none; justify-content: center; align-items: center; z-index: 1000; } .modal-content { background-color: #fff; padding: 30px; border-radius: 8px; width: 400px; max-width: 90%; } .modal-content h3 { margin-bottom: 20px; text-align: center; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 8px; font-size: 14px; } .form-group input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; outline: none; } .modal-footer { display: flex; gap: 15px; justify-content: flex-end; margin-top: 30px; } .cancel-btn { padding: 8px 20px; border: 1px solid #ddd; background-color: #fff; border-radius: 6px; cursor: pointer; } .confirm-btn { padding: 8px 20px; background-color: #27ae60; color: #fff; border: none; border-radius: 6px; cursor: pointer; }运行与打包命令# 1. 安装依赖 npm install # 2. 启动开发环境热更新 npm run start # 3. 打包应用生成可执行文件 npm run package # 4. 生成安装包 npm run make作业验收标准项目可正常启动无报错应用窗口正常显示功能完整可用。单词增删改查、分类筛选、搜索过滤功能正常数据可持久化存储。单词导入导出功能正常系统菜单可正常使用。代码符合Electron安全规范主进程与渲染进程职责分离IPC通信逻辑正确。可正常打包生成对应平台的安装包安装后可正常运行。代码规范注释清晰结构合理完整覆盖课程核心知识点。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2466952.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!