经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Node.js » 查看文章
WPF 应用迁移到 Electron 框架过程记录
来源:cnblogs  作者:he55  时间:2024/3/7 9:12:42  对本文有异议

前一段时间我用 WPF 开发了一个查看 emoji 表情的小工具 https://github.com/he55/EmojiViewer ,由于最近我使用 macOS 系统比较多,我想能在 macOS 系统上也能使用这个工具。于是我尝试将 WPF 应用迁移到 Electron 框架,感觉这个框架很强大,在这里记录一下应用迁移的过程。

安装 Electron 环境

  • 安装 nodejs。到官网 https://nodejs.org/en 下载最新的 nodejs,然后安装
  • 打开命令行输入 git clone https://github.com/electron/electron-quick-start.git 命令克隆 Electron 模板项目,使用模板可以快速搭建应用。
  • 然后使用 cd electron-quick-start 目录进入到目录,接着运行 npm install 命令还原项目。
  • 使用 vscode 打开文件夹,项目文件如下

编写代码

  • Electron 分为主进程和渲染进程,对文件、系统和窗口的操作需要在主线程,界面渲染在渲染进程。创建窗口属于主进程的工作,需要到 main.js 文件编写代码。创建窗口使用 BrowserWindow 对象,widthheight 分别设置窗口宽度和高度,autoHideMenuBar 设置是否隐藏菜单,最后使用 loadFile 加载页面文件并显示窗口。
  1. function createWindow() {
  2. const mainWindow = new BrowserWindow({
  3. width: 915,
  4. height: 560,
  5. autoHideMenuBar: true,
  6. webPreferences: {
  7. preload: path.join(__dirname, 'preload.js')
  8. }
  9. })
  10. mainWindow.loadFile('index.html')
  11. }
  • 监听 whenReady 事件,等待应用初始化完成后显示窗口
  1. app.whenReady().then(() => {
  2. createWindow()
  3. app.on('activate', function () {
  4. if (BrowserWindow.getAllWindows().length === 0) createWindow()
  5. })
  6. })
  • 修改 index.html 文件,界面部分使用了 vue 进行渲染
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <script src="vue.global.js"></script>
  6. <link href="./styles.css" rel="stylesheet">
  7. <title>EmojiViewer</title>
  8. </head>
  9. <body>
  10. <div id="app" class="container">
  11. <ul class="left">
  12. <li v-for="(item, key) in categories" :class="{active: item.isActive}" @click="catetoryItemClick(item)">{{ key }}</li>
  13. </ul>
  14. <ul class="main" ref="mainElement">
  15. <li v-for="emoji in emojis" :class="{active: emoji.isActive}" @click="emojiItemClick(emoji)">
  16. <img :src="emoji.previewImage" alt="">
  17. <p>{{emoji.name}}</p>
  18. </li>
  19. </ul>
  20. <div class="right">
  21. <img :src="selectedEmoji.previewImage">
  22. <p>{{ selectedEmoji.name }}</p>
  23. <button @click="copyEmoji(selectedEmoji)" type="button">Copy Emoji</button>
  24. <button @click="copyImage(selectedEmoji)" type="button">Copy Image</button>
  25. <button @click="openFile(selectedEmoji)" type="button">Open File</button>
  26. </div>
  27. </div>
  28. <script src="./renderer.js"></script>
  29. </body>
  30. </html>
  • renderer.js 文件中编写页面处理代码
  1. window.addEventListener('DOMContentLoaded', async () => {
  2. const { createApp, ref, onMounted } = Vue
  3. let emojiData = await ipc.getData()
  4. createApp({
  5. setup() {
  6. const mainElement = ref(null)
  7. const categories = ref(emojiData)
  8. const emojis = ref([])
  9. const selectedEmoji = ref({})
  10. function copyEmoji(emoji) {
  11. ipc.ipc('writeText', emoji.metadata.glyph)
  12. }
  13. function copyImage(emoji) {
  14. ipc.ipc('writeImage', emoji.previewImage)
  15. }
  16. function openFile(emoji) {
  17. ipc.ipc('showItemInFolder', emoji.previewImage)
  18. }
  19. let lastSelectedEmojis
  20. function catetoryItemClick(items) {
  21. if (lastSelectedEmojis) {
  22. lastSelectedEmojis.isActive = false
  23. }
  24. items.isActive = true
  25. lastSelectedEmojis = items
  26. // const main = document.querySelector('.main')
  27. mainElement.value.scrollTop = 0
  28. emojis.value = items
  29. }
  30. function emojiItemClick(emoji) {
  31. if (selectedEmoji.value) {
  32. selectedEmoji.value.isActive = false
  33. }
  34. emoji.isActive = true
  35. selectedEmoji.value = emoji
  36. }
  37. onMounted(() => {
  38. catetoryItemClick(emojiData['Activities'])
  39. emojiItemClick(emojiData['Activities'][0])
  40. })
  41. return {
  42. mainElement,
  43. categories,
  44. emojis,
  45. selectedEmoji,
  46. catetoryItemClick,
  47. emojiItemClick,
  48. copyEmoji,
  49. copyImage,
  50. openFile,
  51. }
  52. }
  53. }).mount('#app')
  54. })
  • 读取文件,node 提供了文件操作相关的 api 可以很方便的操作文件系统。
  1. function loadData(assetPath) {
  2. const dirs = fs.readdirSync(assetPath)
  3. const data = []
  4. const groupData = {}
  5. for (const dir of dirs) {
  6. const fullPath = path.resolve(assetPath, dir)
  7. const metadata = require(path.resolve(fullPath, 'metadata.json'))
  8. let previewImage
  9. let imagePaths = [path.resolve(fullPath, '3D'), path.resolve(fullPath, 'Default', '3D')]
  10. for (const imagePath of imagePaths) {
  11. if (fs.existsSync(imagePath)) {
  12. let files = fs.readdirSync(imagePath)
  13. if (files.length === 0)
  14. return
  15. previewImage = path.resolve(imagePath, files[0])
  16. }
  17. }
  18. const { unicode, group } = metadata
  19. const obj = {
  20. metadata,
  21. id: unicode,
  22. name: dir,
  23. previewImage,
  24. }
  25. data.push(obj)
  26. if (!groupData[group])
  27. groupData[group] = []
  28. groupData[group].push(obj)
  29. }
  30. return groupData
  31. }

完整代码(WPF 版本) https://github.com/he55/EmojiViewer
完整代码(vue 版本) https://github.com/he55/web-learn/tree/main/9.electron-emoji-viewer(vue)
完整代码(js 原生版本) https://github.com/he55/web-learn/tree/main/6.electron-emoji-viewer

原文链接:https://www.cnblogs.com/he55/p/18046511

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号