Electron基础

文档地址: https://www.electronjs.org/

process.platform:获取平台
Ctrl + Shift + i :调出调试面板

技术架构

  • Chromium:支持最新特性的浏览器
  • Node.js:JavaScript 运行时,可实现文件读写等
  • Native APIs:提供统一的原生界面能力

Electron 工作流程
在这里插入图片描述
在这里插入图片描述
主进程

  • 可以看做是 package.json 中 main 属性对应的文件
  • 一个应用只会有一个主进程
  • 只有主进程可以进行 GUI 的 API 操作

渲染进程

  • Windows 中展示的界面通过渲染进程表现
  • 一个应用可以有多个渲染进程

环境搭建

# 克隆示列项目的仓库
git clone https://github.com/electron/electron-quick-start

# 进入这个仓库
cd electron-quick-start

# 安装依赖并运行
npm install && npm start

Electron 生命周期

  • ready:app 初始化完成
  • dom-ready:一个窗口中的文本加载完成
  • did-finish-load:导航完成时触发
  • window-all-closed:所有窗口都被关闭时触发
  • before-quit:在关闭窗口之前触发
  • will-quit:在窗口关闭并且应用退出时触发
  • quit:当所有窗口被关闭时触发
  • close:当窗口关闭时触发,此时应删除窗口引用

窗口尺寸

const { app, BrowserWindow } = require('electron')

// 将创建窗口独立成一个函数
function createWindow() {
  let mainWin = new BrowserWindow({
    x: 100,
    y: 100,  // 设置窗口显示的位置,相对于当前屏幕的左上角
    show: false,  // 默认情况下创建一个窗口对象之后就会显示,设置为false 就不会显示了
    width: 800,
    height: 400,
    maxHeight: 600,
    maxWidth: 1000,
    minHeight: 200,
    minWidth: 300,  // 可以通过 min max 来设置当前应用窗口的最大和最小尺寸
    resizable: false  // 是否允许缩放应用的窗口大小 
  })

  mainWin.loadFile('index.html')
  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })
  mainWin.on('close', () => {
    console.log('mainWin is closed')
    mainWin = null
  })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
  console.log('all window is closed')
  app.quit()
})

窗口标题

let mainWin = new BrowserWindow({
    show: true,
    width: 800,
    height: 600,
    frame: true,  // 用于自定义 menu ,设置为 false 可以将默认的菜单栏隐藏
    // transparent: true,
    autoHideMenuBar: true,
    icon: 'lg.ico',  // 设置一个图片路径,可以自定义当前应用的显示图标
    title: "拉勾教育",  // 自定义当前应用的显示标题
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })

自定义窗口实现

 let mainWin = new BrowserWindow({
    frame: false,
    width: 800,
    height: 400,
    webPreferences: {  // 用于控制窗口加载的网页是否集成 node.js 环境
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })
const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {

  // 利用 remote 可以获取当前窗口对象
  let mainWin = remote.getCurrentWindow()

  // 获取元素添加点击操作的监听
  let aBtn = document.getElementsByClassName('windowTool')[0].getElementsByTagName('div')

  aBtn[0].addEventListener('click', () => {
    // 当前事件发生后说明需要关闭窗口
    mainWin.close()
  })

  aBtn[1].addEventListener('click', () => {
    // 这里需要执行的最大化操作
    console.log(mainWin.isMaximized())
    if (!mainWin.isMaximized()) {
      mainWin.maximize()  // 让当前窗口最大化
    } else {
      mainWin.restore()  // 回到原始的状态
    }
  })

  aBtn[2].addEventListener('click', () => {
    // 实现最小化
    if (!mainWin.isMinimized()) {
      mainWin.minimize()
    }
  })
})

阻止窗口关闭

const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {
  // 阻止窗口关闭
  window.onbeforeunload = function () {
    let oBox = document.getElementsByClassName('isClose')[0]
    oBox.style.display = 'block'

    let yesBtn = oBox.getElementsByTagName('span')[0]
    let noBtn = oBox.getElementsByTagName('span')[1]

    yesBtn.addEventListener('click', () => {
      mainWin.destroy()
    })

    noBtn.addEventListener('click', () => {
      oBox.style.display = 'none'
    })

    return false
  }

  // 利用 remote 可以获取当前窗口对象
  let mainWin = remote.getCurrentWindow()

  // 获取元素添加点击操作的监听
  let aBtn = document.getElementsByClassName('windowTool')[0].getElementsByTagName('div')

  aBtn[0].addEventListener('click', () => {
    // 当前事件发生后说明需要关闭窗口
    mainWin.close()
  })
})

父子及模态窗口

const { remote } = require('electron')

window.addEventListener('DOMContentLoaded', () => {
  let oBtn = document.getElementById('btn')
  oBtn.addEventListener('click', () => {
    let subWin = new remote.BrowserWindow({
      parent: remote.getCurrentWindow(),
      width: 200,
      height: 200,
      modal: true
    })
    subWin.loadFile('sub.html')
    subWin.on('close', () => {
      subWin = null
    })
  })
})

自定义菜单角色及类型

const { app, BrowserWindow, Menu } = require('electron')

const createWindow = function () {
  let mainWin = new BrowserWindow({
    show: false,
    width: 800,
    height: 600,
    icon: './lg.ico',
    title: '拉勾教育',
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })

  // 01 自定义菜单的内容
  let menuTemp = [
    {
      label: '角色',
      submenu: [
        { label: '复制', role: 'copy' },
        { label: '剪切', role: 'cut' },
        { label: '粘贴', role: 'paste' },
        { label: '最小化', role: 'minimize' },
      ]
    },
    {
      label: '类型',
      submenu: [
        { label: '选项1', type: 'checkbox' },
        { label: '选项2', type: 'checkbox' },
        { label: '选项3', type: 'checkbox' },
        { type: "separator" },
        { label: 'item1', type: "radio" },
        { label: 'item2', type: "radio" },
        { type: "separator" },
        { label: 'windows', type: 'submenu', role: 'windowMenu' }
      ]
    },
    {
      label: '其它',
      submenu: [
        {
          label: '打开',
          icon: './open.png',
          accelerator: 'ctrl + o',
          click() {
            console.log('open操作执行了')
          }
        }
      ]
    }
  ]

  // 02 依据上述的数据创建一个 menu 
  let menu = Menu.buildFromTemplate(menuTemp)

  // 03 将上述的菜单添加至 app 身上
  Menu.setApplicationMenu(menu)

  mainWin.loadFile('index.html')

  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })

  mainWin.on('close', () => {
    mainWin = null
  })
}

app.on('ready', () => {
  createWindow()
})

app.on('window-all-closed', () => {
  app.quit()
})

动态创建菜单

const { remote } = require('electron')
const Menu = remote.Menu
const MenuItem = remote.MenuItem

window.addEventListener('DOMContentLoaded', () => {
  // 获取要应的元素
  let addMenu = document.getElementById('addMenu')
  let menuCon = document.getElementById('menuCon')
  let addItem = document.getElementById('addItem')

  // 自定义全局变量存放菜单项
  let menuItem = new Menu()

  // 生成自定义的菜单
  addMenu.addEventListener('click', () => {
    // 创建菜单 
    let menuFile = new MenuItem({ label: '文件', type: 'normal' })
    let menuEdit = new MenuItem({ label: '编辑', type: 'normal' })
    let customMenu = new MenuItem({ label: '自定义菜单项', submenu: menuItem })

    // 将创建好的自定义菜单添加至 menu 
    let menu = new Menu()
    menu.append(menuFile)
    menu.append(menuEdit)
    menu.append(customMenu)

    // 将menu 放置于 app 中显示
    Menu.setApplicationMenu(menu)
  })

  // 动态添加菜单项
  addItem.addEventListener('click', () => {
    // 获取当前 input 输入框当中的内容
    let con = menuCon.value.trim()
    if (con) {
      menuItem.append(new MenuItem({ label: con, type: 'normal' }))
      menuCon.value = ''
    }
  })
})

右键菜单

  • 创建一个自定义的菜单内容
  • 在鼠标右击行为发生后显示出来
const { remote } = require('electron')
const Menu = remote.Menu

// 定义菜单的内容
let contextTemp = [
  { label: 'Run Code' },
  { label: '转到定义' },
  { type: 'separator' },
  {
    label: '其它功能',
    click() {
      console.log('其它功能选项被点击了')
    }
  },
]

// 依据上述的内容来创建 menu 
let menu = Menu.buildFromTemplate(contextTemp)

// 给鼠标右击添加监听
window.addEventListener('DOMContentLoaded', () => {
  window.addEventListener('contextmenu', (ev) => {
    ev.preventDefault()
    menu.popup({ window: remote.getCurrentWindow() })
  }, false)
})

主进程与渲染进程通信

const { app, BrowserWindow, ipcMain, Menu } = require('electron')

const createWindow = function () {

  let mainWin = new BrowserWindow({
    show: false,
    width: 800,
    title: '拉勾教育',
    height: 400,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true,
    }
  })

  let temp = [
    {
      label: 'send',
      click() {
        BrowserWindow.getFocusedWindow().webContents.send('mtp', '来自于自进程的消息')
      }
    }
  ]

  let menu = Menu.buildFromTemplate(temp)
  Menu.setApplicationMenu(menu)

  mainWin.loadFile('index.html')
  mainWin.webContents.openDevTools()

  mainWin.on('ready-to-show', () => {
    mainWin.show()
  })

  mainWin.on('close', () => {
    mainWin = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  app.quit()
})

// 主进程接收消息操作
ipcMain.on('msg1', (ev, data) => {
  console.log(data)
  ev.sender.send('msg1Re', '这是一条来自于主进程的异步消息')
})

ipcMain.on('msg2', (ev, data) => {
  console.log(data)
  ev.returnValue = '来自于主进程的同步消息'
})
const { ipcRenderer } = require('electron')

window.onload = function () {
  // 获取元素
  let aBtn = document.getElementsByTagName('button')

  // 01 采用异步的 API 在渲染进程中给主进程发送消息
  aBtn[0].addEventListener('click', () => {
    ipcRenderer.send('msg1', '当前是来自于渲染进程的一条异步消息')
  })

  // 02 采用同步的方式完成数据通信
  aBtn[1].addEventListener('click', () => {
    let val = ipcRenderer.sendSync('msg2', '同步消息')
    console.log(val)
  })


  // 当前区域是接收消息
  ipcRenderer.on('msg1Re', (ev, data) => {
    console.log(data)
  })

  ipcRenderer.on('mtp', (ev, data) => {
    console.log(data)
  })
}

渲染进程间通信

  • 通过 localStorage 通信

基于主进程的进程通信

// 接收其它进程发送的数据,然后完成后续的逻辑
ipcMain.on('openWin2', (ev, data) => {
  // 接收到渲染进程中按钮点击信息之后完成窗口2 的打开
  let subWin1 = new BrowserWindow({
    width: 400,
    height: 300,
    parent: BrowserWindow.fromId(mainWinId),
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true
    }
  })
  subWin1.loadFile('subWin1.html')

  subWin1.on('close', () => {
    subWin1 = null
  })

  // 此时我们是可以直接拿到 sub 进程的窗口对象,因此我们需要考虑的就是等到它里面的所有内容
  // 加载完成之后再执行数据发送
  subWin1.webContents.on('did-finish-load', () => {
    subWin1.webContents.send('its', data)
  })
})

ipcMain.on('stm', (ev, data) => {
  // 当前我们需要将 data 经过 main 进程转交给指定的渲染进程
  // 此时我们可以依据指定的窗口 ID 来获取对应的渲染进程,然后执行消息的发送
  let mainWin = BrowserWindow.fromId(mainWinId)
  mainWin.webContents.send('mti', data)
})

Dialog 模块

const { remote } = require('electron')

window.onload = function () {
  let oBtn = document.getElementById('btn')
  let oBtnErr = document.getElementById('btnErr')

  oBtn.addEventListener('click', () => {
    remote.dialog.showOpenDialog({
      defaultPath: __dirname,
      buttonLabel: '请选择',
      title: '拉勾教育',
      properties: ['openFile', 'multiSelections'],
      filters: [
        { "name": '代码文件', extensions: ['js', 'json', 'html'] },
        { "name": '图片文件', extensions: ['ico', 'jpeg', 'png'] },
        { "name": '媒体类型', extensions: ['avi', 'mp4', 'mp3'] }
      ]
    }).then((ret) => {
      console.log(ret)
    })
  })


  oBtnErr.addEventListener('click', () => {
    remote.dialog.showErrorBox('自定义标题', '当前错误内容')
  })
}

shell 与 iframe

  • shell 为在浏览器标签页中打开链接
  • iframe 是在桌面应用中打开
const { app, BrowserWindow, shell, Menu } = require('electron')
// ...
shell.openExternal('https://kaiwu.lagou.com/')

消息通知

  • 基于 H5 实现消息通知
window.onload = function () {
  let oBtn = document.getElementById('btn')

  oBtn.addEventListener('click', () => {
    let option = {
      title: '拉勾教育',
      body: '互联网人的实战大学,大前端',
      icon: './msg.png'
    }

    let myNotification = new window.Notification(option.title, option)

    myNotification.onclick = function () {
      console.log('点击了消息页卡')
    }
  })
}

注册快捷键

const { app, BrowserWindow, globalShortcut } = require('electron')

app.on('ready', () => {
  // 注册
  let ret = globalShortcut.register('ctrl + q', () => {
    console.log('快捷键注册成功')
  })

  if (!ret) {
    console.log('注册失败')
  }

  console.log(globalShortcut.isRegistered('ctrl + q'))

  console.log(ret, '~~~~~')

})

app.on('will-quit', () => {
  console.log(666)
  globalShortcut.unregister('ctrl + q')
  globalShortcut.unregisterAll()
})

剪切版操作

const { clipboard, nativeImage } = require('electron')

window.onload = function () {
  // 获取元素
  let aBtn = document.getElementsByTagName('button')
  let aInput = document.getElementsByTagName('input')
  let oBtn = document.getElementById('clipImg')
  let ret = null

  aBtn[0].onclick = function () {
    // 复制内容
    ret = clipboard.writeText(aInput[0].value)
  }

  aBtn[1].onclick = function () {
    // 粘贴内容
    aInput[1].value = clipboard.readText(ret)
  }

  oBtn.onclick = function () {
    // 将图片放置于剪切板当中的时候要求图片类型属于 nativeImage 实例
    let oImage = nativeImage.createFromPath('./msg.png')
    clipboard.writeImage(oImage)

    // 将剪切板中的图片做为 DOM 元素显示在界面上
    let oImg = clipboard.readImage()
    let oImgDom = new Image()
    oImgDom.src = oImg.toDataURL()
    document.body.appendChild(oImgDom)
  }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值