当前位置: 首页 > article >正文

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通信逻辑正确。可正常打包生成对应平台的安装包安装后可正常运行。代码规范注释清晰结构合理完整覆盖课程核心知识点。

相关文章:

JavaScript基础课程三十三、性能优化与工程化高级

本课是前端从入门到高级开发的核心进阶课,聚焦性能优化与高级工程化两大核心能力。性能优化以用户体验为核心,覆盖渲染、构建、网络全链路,从指标检测到落地优化,形成完整的优化方法论;高级工程化则是企业级项目开发的…...

ESP32Cam与YOLOv3构建边缘图像识别系统

1. 项目概述:ESP32CamYOLOv3图像识别系统这个项目构建了一个完整的嵌入式图像识别系统,核心由ESP32Cam模块和YOLOv3算法组成。作为一名长期从事嵌入式视觉开发的工程师,我认为这种组合是目前性价比最高的边缘计算视觉方案之一。ESP32Cam模块集…...

OMO·赶考小状元AI自习室:破解线下自习室困局,引领学习新范式

近年来,一个有趣的现象在教培领域悄然发生:传统线下自习室逐渐遇冷,客流量与用户粘性面临挑战;而与此同时,一种名为“AI自习室”的新形态却异军突起,展现出强大的市场吸引力。这背后,并非简单的…...

Libero SoC v2021.1离线安装全攻略:从下载到IP核配置(附避坑指南)

Libero SoC v2021.1离线安装全攻略:从下载到IP核配置(附避坑指南) 在企业内网开发环境中,离线安装EDA工具往往面临诸多挑战。本文将手把手指导您完成Libero SoC v2021.1的完整离线部署流程,涵盖从安装包获取到IP核配置…...

yuzu模拟器中文显示问题深度解析与专业调校指南

yuzu模拟器中文显示问题深度解析与专业调校指南 【免费下载链接】yuzu-downloads 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu-downloads yuzu模拟器作为目前最优秀的任天堂Switch模拟器,在运行中文游戏时常常面临字体渲染和显示兼容性问题。本…...

用MQTT协议玩转OneNet物联网:STM32F103+ESP8266实现温湿度监控(附心跳包优化技巧)

STM32F103与ESP8266的物联网实战:MQTT协议深度优化与温湿度监控系统设计 1. 资源受限环境下的物联网通信架构设计 在嵌入式物联网设备开发中,资源优化始终是核心挑战。STM32F103C8T6作为经典的Cortex-M3内核微控制器,仅有64KB Flash和20KB RA…...

从‘它又挂了’到‘稳如老狗’:我是如何用Prometheus+Grafana给自家小破站做监控的

从“它又挂了”到“稳如老狗”:我是如何用PrometheusGrafana给自家小破站做监控的 凌晨三点,手机突然响起钉钉告警——这已经是本周第三次被“502 Bad Gateway”的提示音吵醒。揉着惺忪睡眼重启Nginx时,我突然意识到:这个用业余时…...

保姆级教程:用C语言数组扫描法,搞定智能车摄像头识别赛道‘L型’拐点

智能车竞赛实战:C语言数组扫描法精准识别L型赛道拐点 在智能车竞赛的赛道上,L型拐点往往是让许多参赛队伍"翻车"的关键节点。传统横向巡线算法在这里容易丢失赛道边界,而基于纵向扫描的数组分析法却能像手术刀般精准定位特征点。本…...

球机器人研究报告【202600001】

文章目录球机器人研究报告综合分析多智能体推箱子训练(第100代/第300代)一、意识流分析(神经网络脉冲活动)1. 热图(consciousness_agent2_gen100_ep0_heatmap.png)2. PCA(主成分分析&#xff0c…...

【ROS2小白入门】从 ROS 1 到 ROS 2 的跨越:实战重构机器人底盘 Manager 节点

文章目录一、 构建系统的蜕变:CMakeLists.txt 的优雅转身1. 告别 target_link_libraries🚨 避坑指南 1:找不到 serial 串口库?二、 C 源码大换血:彻底消灭 NodeHandle三、 通信机制迁移:发布、订阅与异步服…...

ArduinoFritzApi:嵌入式设备对接FRITZ!Box的TR-064协议实践

1. ArduinoFritzApi 库深度解析:面向嵌入式系统的 FRITZ!Box 自动化控制实践指南1.1 库定位与工程价值ArduinoFritzApi 是一个专为嵌入式平台设计的轻量级 C 库,其核心目标是实现对 AVM 公司全系智能家庭设备(FRITZ!Box 路由器、FRITZ!DECT 插…...

手把手教你搭建基于Matlab/Simulink的插电式混合动力汽车4驱PHEV模型

基于Matlab/simulink的插电式混合动力汽车建模仿真模型4驱PHEV(比亚迪唐DM混动系统P2P4发动机——三擎四驱),包括整车HCU控制单元、发动机模型、驱动电机模型、ISG电机模型、AMT5档自动变速箱模型、驾驶员模型、电池能量管理控制模型等&#…...

EspNowBus:ESP32轻量级安全无线总线库

1. EspNowBus 项目概述 EspNowBus 是一个面向 ESP32 平台、以组(Group)为组织单元的轻量级 ESP-NOW 消息总线库,专为小型嵌入式无线网络(典型规模 ≈6 节点)设计。其核心工程目标并非追求最大吞吐或最广覆盖&#xff0…...

JPom结合Docker实现SpringBoot项目自动化构建与部署实战

1. 为什么你需要JPomDocker自动化部署方案 每次手动打包SpringBoot项目时,你是不是也经历过这样的痛苦?先在本地mvn clean package,然后scp上传到服务器,接着ssh连上去kill旧进程,最后nohup启动新jar包。更可怕的是半夜…...

3D建模快速上手:零门槛掌握TripoSR AI驱动开源工具

3D建模快速上手:零门槛掌握TripoSR AI驱动开源工具 【免费下载链接】TripoSR 项目地址: https://gitcode.com/GitHub_Trending/tr/TripoSR 在数字创作领域,3D建模曾是专业人士的专属技能,需要掌握复杂的软件操作和几何知识。但今天&a…...

事件驱动RTOS EventOS的创新设计与应用实践

1. 事件驱动型RTOS的创新设计 在嵌入式系统开发领域,实时操作系统(RTOS)一直是关键基础设施。传统RTOS如FreeRTOS、uC/OS等大多采用基于时间片轮转的任务调度机制,而EventOS则开创性地采用了事件驱动架构,这在资源受限的嵌入式环境中具有独特…...

【等保三级Java系统合规落地指南】:20年安全架构师亲授7大关键改造步骤与避坑清单

第一章:等保三级Java系统合规落地的顶层认知与法律依据等保三级(GB/T 22239–2019《信息安全技术 网络安全等级保护基本要求》)并非单纯的技术加固任务,而是覆盖组织管理、制度建设、技术实施与持续运营的全生命周期合规工程。对J…...

7个技巧彻底改变你的Mac菜单栏体验:Ice终极配置指南

7个技巧彻底改变你的Mac菜单栏体验:Ice终极配置指南 【免费下载链接】Ice Powerful menu bar manager for macOS 项目地址: https://gitcode.com/GitHub_Trending/ice/Ice Ice是一款强大的macOS菜单栏管理工具,专门帮助用户整理杂乱的菜单栏图标&…...

从零打造你的CAD开发环境:用OpenCASCADE 7.7.0 + VS2022画个3D盒子(完整Debug/Release配置)

从零打造你的CAD开发环境:用OpenCASCADE 7.7.0 VS2022画个3D盒子(完整Debug/Release配置) 当你第一次尝试在Visual Studio中配置OpenCASCADE(OCCT)时,可能会被那些复杂的路径设置、库文件链接和环境变量搞…...

探索DevOps之路:2024年DevOps路线图

探索DevOps之路:2024年DevOps路线图 【免费下载链接】DevOps-Roadmap DevOps Roadmap for 2026. with learning resources 项目地址: https://gitcode.com/GitHub_Trending/de/DevOps-Roadmap 项目介绍 DevOps Roadmap 2024 是一个精心设计的步骤指南&#…...

VIT模型IP核需要修改的地方

导入路径 "D:\VIT\HG-PIPE\instances\proj_ATTN0\work"选择“open project”整合多个 HLS IP 时 遇到“撞名”此时会报错:Top function not found: there is no function named top INFO: [HLS 200-1510] Running: set_directive_top -name top top...

太吾绘卷Mod终极指南:从零开始打造个性化游戏体验

太吾绘卷Mod终极指南:从零开始打造个性化游戏体验 【免费下载链接】Taiwu_mods 太吾绘卷游戏Mod 项目地址: https://gitcode.com/gh_mirrors/ta/Taiwu_mods 想要为《太吾绘卷》注入全新活力吗?太吾绘卷Mod为这款经典游戏带来了无限可能&#xff0…...

AD5246数字电位器驱动库详解与I²C工程实践

1. AD5246 数字电位器库深度技术解析1.1 器件本质与工程定位AD5246 并非传统意义上的“可编程电阻”,而是一款单通道、IC 接口、128 抽头数字可变电阻器(Digital Rheostat)。其核心价值在于以数字方式精确控制模拟电路中的阻值,替…...

AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景

AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景 清晨被智能闹钟以最舒适的渐强音量唤醒,通勤路上听着音乐App精准推荐的歌单,晚上回家对着冰箱说出想吃的菜谱——这些场景中隐藏的AI技术,早已像水电一样成为生活基础设施。…...

3D重建效率革命:从单张图片到高质量模型的全流程指南

3D重建效率革命:从单张图片到高质量模型的全流程指南 【免费下载链接】TripoSR 项目地址: https://gitcode.com/GitHub_Trending/tr/TripoSR 在数字内容创作领域,3D建模长期面临两大核心痛点:一方面,传统3D建模软件如Blen…...

ESP32-CAM人脸识别从入门到实战:5步搞定考勤系统(附完整代码)

ESP32-CAM人脸识别考勤系统实战指南:低成本高精度部署方案 引言:重新定义考勤管理的技术革新 在传统考勤方式逐渐显露出效率瓶颈的今天,基于ESP32-CAM的人脸识别技术为中小企业和教育机构提供了一种革命性的解决方案。这套系统不仅突破了传统…...

永磁同步电机的 MTPA + 弱磁控制算法 Simulink 模型探索

永磁同步电机的MTPA弱磁控制算法simulink模型。 转速从4000变到16000转,效果较好,附赠核心模型对应公式文档。在电机控制领域,永磁同步电机(PMSM)因其高效、高功率密度等优点,被广泛应用于各种工业和民用场…...

研发物料管理新思路:巧用SAP预留功能实现打样耗材精准管控

研发物料管理新思路:巧用SAP预留功能实现打样耗材精准管控 在制造业研发部门,物料管理一直是令人头疼的难题。不同于生产线的标准化流程,研发活动往往伴随着频繁的设计变更、小批量试制和突发性物料需求。传统的手工台账或Excel表格管理方式&…...

SteamShutdown:智能下载管理与自动化电源控制的创新解决方案

SteamShutdown:智能下载管理与自动化电源控制的创新解决方案 【免费下载链接】SteamShutdown Automatic shutdown after Steam download(s) has finished. 项目地址: https://gitcode.com/gh_mirrors/st/SteamShutdown 在数字娱乐时代,游戏下载已…...

从脑电波到股票K线:EMD经验模态分解在5个真实场景下的避坑指南

从脑电波到股票K线:EMD经验模态分解在5个真实场景下的避坑指南 当你第一次看到脑电波信号与股票K线图被放在同一个分析框架下讨论时,可能会觉得这是两个毫不相关的领域。但事实上,无论是神经科学家的EEG数据,还是量化交易员的股价…...