• Electron桌面开发入门


    1.初始化工作

    midir electron-demo
    cd electron-demo
    npm init
    
    //到package.json 文件下将入口文件修改为main.js
      "main": "main.js",
    //并且创建main.js文件
    
    //electron 安装依赖
    npm i electron -S
    //安装nodemon 
    npm install nodemon -D
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    修改package.json

    {
      "name": "electron-demo",
      "version": "1.0.0",
      "description": "",
      "main": "main.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "nodemon --exec electron . --watch ./ --ext .html,.js,.css"    //监听html,js,css文件的变化
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "electron": "^19.0.6",
        "electron-win-state": "^1.1.22"
      },
      "devDependencies": {
        "nodemon": "^2.0.16"
      }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    修改main.js

    //app应用模块
    //BrowserWindow 浏览器串口模块
    const { app, BrowserWindow } = require('electron')
    
    //创建窗口
    const createwindow = ()=>{
      const win = new BrowserWindow({
        width:800,
        height:600
      })
    
      // 给窗口装载页面
      // win.loadFile('./renderer/index.html')
      win.loadURL('https://cn.bing.com/?mkt=zh-CN')
    
      //自动打开发开工具
      win.webContents.openDevTools()
    
    
      //可以创建多个窗口
    //   const win2 = new BrowserWindow({
    //     width:800,
    //     height:600
    //   })
    
    //   win2.loadURL('https://www.baidu.com')
    }
    
    //应用就绪,可以装载窗口了
    app.whenReady().then(createwindow)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    启动程序

    npm start
    
    • 1

    看到效果
    在这里插入图片描述
    后续操作省略,可以对应文件夹实现
    目录如下
    在这里插入图片描述
    main.js 主程序文件 node环境,能读写文件
    renderer 渲染文件 有关页面渲染的都在这里,可以结合vue等框架
    app.js //vue模板
    index.html //窗口页面
    style.css //窗口样式文件
    preload-js 桥接文件
    因为渲染程序和主程序直接传递消息有严重的安全隐患,所以要通过这里的’桥’文件,当工具人这里面重要的核心就是通过contextBridge 暴露一个对象给渲染程序通过ipcRenderer中的方法监听和抛发事件
    controller 主程序事件控制器
    主要处理主程序监听事件和抛发事件的逻辑处理
    具体操作如下

    main.js

    // 引入事件处理器,对render的操作作出回应
    require('./controller/ipcMessage')
    
    //引入插件    作用:记录窗口的位置大小
    const  WinState = require('electron-win-state').default
    
    //app应用模块
    //BrowserWindow 浏览器串口模块
    const { app, BrowserWindow } = require('electron')
    const {resolve} =require('path') 
    //创建窗口
    const createwindow = ()=>{
    
      // 设置默认窗口大小
      const  winState = new WinState({ 
        defaultWidth: 1400,
        defaultHeight: 600,
        dev:true
      })
    
      const win = new BrowserWindow({
        ...winState.winOptions,
        // width:800,
        // height:600,
        show:false,
        minHeight:300,
        minWidth:400,
       
        backgroundColor: 'aliceblue',
        resizable:true, //默认可以 切换窗口大小
        movable:true,  //窗口是否可以移动
        // frame:true,  //是否关闭边框
        // titleBarStyle: "hidden",  // 控制titleBar的状态
        backgroundColor:"skyblue",
        webPreferences:{
          //nodeIntegration 开启node  contextIsolation 开启或关闭主程序和渲染程序的隔离 
          //这两个的开启会有安全隐患 
          // nodeIntegration:true,
          // contextIsolation:false    
    
          //预加载,桥文件
          preload: resolve(__dirname,'./preload-js')
        }
      })
    
      //将窗口位置大小存起来
      winState.manage(win)
    
      // 给窗口装载页面
      win.loadFile('./renderer/index.html')
      // win.loadURL('https://cn.bing.com/?mkt=zh-CN')
    
      //自动打开发开工具
      // win.webContents.openDevTools()
    
      //同win 的show一起配置 当win装载完成显示
      win.once('ready-to-show',()=>{
        win.show()
      })
      // 可以创建多个窗口
      // const win2 = new BrowserWindow({
      //   width:800,
      //   height:600,
      //   parent:win,  //配置父窗口,这里是子窗口
      //   modal:false   //锁定子窗口
      // })
    
      // win2.loadURL('https://www.baidu.com')
      //win2 关闭时 win 全屏
      // win2.on('close',()=>{
      //   win.maximize()
      // })
    }
    
    //app主进程完成加载
    // app.on('will-finish-launching',()=>{
    //   console.log('will-finish-launching')
    // })
    // //app准备就绪
    // app.on('ready',()=>{
    //   console.log('ready')
    // })
    
    // // app将要退出
    // app.on('will-quit',()=>{
    //   console.log('will-quit')
    // })
    
    // app.on('before-quit',()=>{
    //   console.log('before-quit')
    // })
    
    // //app退出
    // app.on('quit',()=>{
    //   console.log('quit')
    // })
    // //所有窗口都关闭
    // app.on('window-all-closed',()=>{
    //   console.log('window-all-closed')
    //   //对于macos系统,关闭窗口时,不会直接退出应用,还会保留图标
    //   // if(process.platform!=='darwin'){
    //   //   app.quit()
    //   // }
    // })
    
    
    //应用就绪,可以装载窗口了
    app.whenReady().then(()=>{
      createwindow()
      //在macos下,当全部窗口都关了,点击图标,窗口再次打开
      app.on('activate',()=>{
        if(BrowserWindow.getAllWindows().length===0){
          createwindow()
        }
      })
    
      //isReady  app是否装载完成
      console.log(app.isReady())
      //获取路径
      console.log(app.getPath('desktop'))
      console.log(app.getPath('music'))
      console.log(app.getPath('temp'))
      console.log(app.getPath('userData'))
    
      console.log(BrowserWindow.getAllWindows().length)
    })
    
    // 程序失焦
    app.on('browser-window-blur',()=>{
      console.log("app blur")
    })
    
    // 程序获取焦点
    app.on('browser-window-focus',()=>{
      console.log('app focus')
    })
    
    // 在html中允许使用第三方资源  设为false 会有警告
    process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    renderer/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <!-- unsafe-eval 配置第三方引用安全策略 -->
      <!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self' unsafe-eval"> -->
      <title>Document</title>
      <script src="./vue.global.js"></script>
      <link rel="stylesheet" href="./style.css">
    </head>
    <body>
      <h1>hello electron!</h1>
      <input type="range" />
      <div id="root"></div>
      <script src="./app.js"></script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    renderer/app.js

    const versions = window.myAPI.versions
    
    const app = Vue.createApp({
      template:`
        <p>Chrome version: {{chromeVersion}}</p>
        <p>Node version: {{NodeVersion}}</p>
        <p>Electron version: {{electronVersion}}</p>
        <button @click="sendSyncMsg"> 发送同步消息 </button>
        <button @click="sendAsyncMsg"> 发送异步消息 </button>
      `,
    
      data(){
        return {
          chromeVersion: versions.chrome,
          NodeVersion: versions.node,
          electronVersion: versions.electron
        }
      },
    
      methods:{
        // 发送同步消息给桥文件,桥文件转发给主程序
        sendSyncMsg(){
          myAPI.sendSyncMsg("this message from render ")
        },
        // 主进程和渲染进程传递消息 建议IPC通信 全部通过异步
        async  sendAsyncMsg(){
          let result = await myAPI.sendAsyncMsg()
          console.log(result)
        }
    
      },
      mounted() {
        // 接受main 返回的消息
        // myAPI.recieveSyncMsgUseCb((msg)=>{
        //   console.log(msg)
        //   console.log(this)
        // })
        //promise调用
        // const result = await myAPI.recieveSyncMsgUsePromise()
        // console.log(result,1111)
        myAPI.recieveSyncMsgUsePromise().then((res)=>{
          console.log(res,22222);
        })
      }
    })
    
    app.mount("#root")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    renderer/style.css

    body {
      background-color: pink;
      /* 设置拖拽 */
      user-select: none;
      -webkit-app-region:drag;
    }
    
    /* 设置input可拖拽 */
    input {
      -webkit-app-region: no-drag;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    preload-js/index.js

    //preload-js下面的文件我把他叫做'桥'文件,桥文件能直接访问到主程序的信息   因为渲染程序不能直接和主程序做通信 有安全隐患
    // 通过桥文件让渲染程序能够获取到主程序的信息
    
    const {contextBridge, ipcRenderer} = require('electron')
    
    // 向main发送一个同步消息
    const sendSyncMsg = (msg)=>{
      console.log(msg,"发送了一次");
      ipcRenderer.send('sync-send-event',msg)
    }
    
    // main收到同步消息抛发事件到这里,通过promise给Vue层
    const recieveSyncMsgUsePromise = ()=>{
      return new Promise((resolve,reject) => {
        ipcRenderer.on('recive-sync-event',(event,msg)=>{
          console.log("返回的数据 1")
          resolve(msg)
        })
      })
    }
    
    // main收到同步消息抛发事件到这里,通过callback给Vue层(推荐使用这种方法)
    const recieveSyncMsgUseCb = (cb) => {
      ipcRenderer.on('recive-sync-event',(event,msg)=>{
        cb(msg)
      })
    }
    
    // 发送异步消息
    const sendAsyncMsg = async ()=>{
      const result = await ipcRenderer.invoke('my-invokable-ipc')
      return result
    }
    
    
    //通过这里向渲染程序暴露一个对象,这个对象是myAPI
    //通过直接暴露ipcRenderer给vue层有些方法会丢失(坑)
    contextBridge.exposeInMainWorld('myAPI',{
      versions: process.versions,
      sendSyncMsg,
      recieveSyncMsgUsePromise,
      sendAsyncMsg,
      recieveSyncMsgUseCb
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    controller/ipcMessage.js

    // 事件处理器  对于桥文件抛发的事件做回应
    const { ipcMain } = require("electron")
    
    ipcMain.on('sync-send-event',(event,msg)=>{
      console.log(msg,'shoudao 1');
      event.reply('recive-sync-event', '我已经收到:' + msg)
      // event.sender.send('a', '我已经收到:' + msg)
    })
    
    function somePromise(){
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          resolve('async message from main')
        },2000)
      })
    }
    // 异步事件监听
    ipcMain.handle("my-invokable-ipc", async (ecent,...args)=>{
      const result = await somePromise()
      return result
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    字符串解码
    猿创征文 |【算法入门必刷】数据结构-栈(六)
    Java连接数据库(JDBC非常重要)
    反范式化设计
    英语——记忆篇——谐音法+拼音法
    基于ssm企业后勤订餐管理系统的设计与实现-计算机毕业设计源码+LW文档
    深度学习 FairMOT多目标跟踪(PANDA)
    许战海战略文库|品类缩量时代:制造型企业如何跨品类打造份额产品?
    每日三题 6.28
    Golang 重返Leetcode战场之旅(Leetcode Go总结博客)
  • 原文地址:https://blog.csdn.net/qq_37905131/article/details/125435345