electron开发技术知识点笔记

窗口和事件

  let mainWindow = new BrowserWindow({
    width: 1000, 
    height: 800,
    webPreferences: {
      contextIsolation: false,
      // 开启了才能是渲染进程使用node
      nodeIntegration: true
    },
    // 窗口是否显示
    show: true,
    // 设置背景,不是css设置的
    backgroundColor: '#92e69c',
    resizable: true,
    movable: true,
    closable: true,
    // 永远在桌面最顶层
    alwaysOnTop: false,
    // 全屏了,宽高没用了,不能关闭了
    fullscreen: false,
    // 开启的话,底部没用程序图标
    skipTaskbar: false,
    icon: 'https://github.githubassets.com/favicons/favicon.png',
  });

  
  mainWindow.loadFile(path.join(__dirname, 'about.html'));
  mainWindow.loadURL('https://google.com')
  
  // 窗口最大
  mainWindow.maximize()

  // 打开开发者工具
  mainWindow.webContents.openDevTools();

  // Listen for window being closed
  mainWindow.on('closed', () => {
    mainWindow = null;
  });
});

app模块事件

// 退出程序
app.quit();

// 获取一些系统路径 
console.log(app.getPath('desktop'))
console.log(app.getPath('music'))
console.log(app.getPath('temp'))
console.log(app.getPath('userData'))

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
  createWindow();
})

app.on('browser-window-focus', e => {
  // console.log('App focused')
});

app.on('browser-window-blur', e => {
  console.log(winState.x, winState.y);
  // console.log('App blur')
});

app.on('before-quit', e => {
  // console.log('Preventing app from quitting')
});

// 在Windows和Linux上,关闭所有窗口通常会完全退出一个应用程序。
// 你需要监听 app 模块的 'window-all-closed' 事件。
// 如果用户不是在 macOS(darwin) 上运行程序,则调用 app.quit()。
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if(process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if(BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

webContents 事件

// 控制右键操作
wc.on('context-menu', (e, params) => {
  contextMenu.popup();
  let selectedText = params.selectionText
  wc.executeJavaScript(`alert("${selectedText}")`)
});

wc.on('media-started-playing', () => {
  console.log('Video Started');
});
wc.on('media-paused', () => {
  console.log('Video Paused');
});

wc.on('login', (e, request, authInfo, callback) => {
  console.log('Logging in:');
  callback('user', 'passwd');
});

wc.on('did-navigate', (e, url, statusCode, message) => {
  console.log(`Navigated to: ${url}`);
  console.log(statusCode);
});

wc.on('new-window', (e, url) => {
  e.preventDefault();
  console.log(`Preventing new window for: ${url}`);
});

wc.on('before-input-event', (e, input) => {
  console.log(`${input.key} : ${input.type}`);
});

wc.on('did-finish-load', () => {
  console.log('Content fully loaded');
});
wc.on('dom-ready', () => {
  console.log('DOM Ready');
});

ipcRenderer 和 ipcMain通信

简单通信

  // 页面上点了按钮
  document.getElementById('create').onclick = function () {
    ipcRenderer.send('window1', 'some data from main view');
  }
  ipcMain.on('window1', (event, data) => {
     console.log(111)
  })

渲染进程通知主线程处理东西,并取得返回值


     ipcRenderer.invoke( 'ask-fruit' ).then( answer => {
       console.log(answer)
     })

    // 主线程这么处理
    async function askFruit () {
      let fruits = ['Apple', 'Orange', 'Grape']
      let choice = await dialog.showMessageBox({
        message: 'Pick a fruit:',
        buttons: fruits
      })
      return fruits[choice.response]
    }

    ipcMain.handle('ask-fruit', e => {

      return askFruit()

    })

preload.js

// preload.js
const fs = require('fs')
const desktopPath = '/Users/David/Desktop'
window.writeToFile = text => {
  fs.writeFile( desktopPath + '/app.txt', text, console.log )
}
window.versions = {
  node: process.versions.node,
  electron: process.versions.electron
}

// main.js
mainWindow = new BrowserWindow({
  width: 1000, height: 800,
  webPreferences: {
    // --- !! IMPORTANT !! ---
    // Disable 'contextIsolation' to allow preload execution
    // 'contextIsolation' defaults to "true" as from Electron v12
    contextIsolation: false,
    nodeIntegration: false,
    preload: __dirname + '/preload.js'
  }
})

// html
<br><textarea id="content" rows="8" cols="80"></textarea>
<br><button id="save" onclick="saveText()">Save Content</button>
<script>
  const saveText = e => {
    const text = document.getElementById('content').value
    writeToFile( text )
  }
</script>

nativeImage图片操作


<button onclick="toPng()">PNG</button>
<button onclick="toJpg()">JPG</button>
<button onclick="toTag()">Show</button>
<br>
<img src="" id="preview">

<script>

  const { nativeImage, ipcRenderer } = require('electron')
  const fs = require('fs')
  const splash = nativeImage.createFromPath(`${__dirname}/splash.png`)

  const saveToDesktop = async ( data, ext ) => {
    // 从主应用得到桌面路径
    let desktopPath = await ipcRenderer.invoke( 'desktop-path' )
    fs.writeFile( `${desktopPath}/splash.${ext}`, data, console.log )
  }

  const toTag = e => {
    let size = splash.getSize()
    let splashURL = splash.resize({ width: Math.round(size.width/4), height: Math.round(size.height/4) }).toDataURL()
    document.getElementById('preview').src = splashURL
  }

  const toPng = e => {
    let pngSplash = splash.toPNG()
    saveToDesktop( pngSplash, 'png' )
  }

  const toJpg = e => {
    let jpgSplash = splash.toJPEG(100)
    // splash.toDataURL
    saveToDesktop( jpgSplash, 'jpg' )
  }

</script>

控制窗口内容缩放

<button onclick="zoomUp()">Increase Zoom</button>
<button onclick="zoomDown()">Decrease Zoom</button>
<button onclick="zoomReset()">Reset Zoom</button>

<script>

  /**
   * 屏幕内容的缩放
   */
  const { webFrame } = require('electron')

  const zoomUp = () => {
    webFrame.setZoomLevel( webFrame.getZoomLevel() + 1 )
  }

  const zoomDown = () => {
    webFrame.setZoomLevel( webFrame.getZoomLevel() - 1 )
  }

  const zoomReset = () => {
    webFrame.setZoomLevel( 1 )
  }

  // console.log( webFrame.getResourceUsage() )

</script>

shell 使用系统默认程序


<button onclick="showSite()">Launch Electron.js Site</button><br>
<button onclick="openSplash()">Open Splash.png</button><br>
<button onclick="showSplashFile()">Show Splash.png</button><br>
<button onclick="deleteSplashFile()">Delete Splash.png</button><br>

<script>

  // shell 使用系统默认程序

  const { shell } = require('electron')

  // 用默认浏览器打开url
  const showSite = e => {
    shell.openExternal('https://electronjs.org')
  }

  const splashPath = `${__dirname}/splash.png`

  // 系统打开图片
  const openSplash = e => {
    shell.openPath(splashPath)
  }

  const showSplashFile = e => {
    shell.showItemInFolder(splashPath)
  }

  const deleteSplashFile = e => {
    shell.moveItemToTrash(splashPath)
  }

</script>

系统托盘

/**
 * 创建系统托盘
 */
const createTray = () => {
  tray = new Tray(path.join(__dirname, "favicon.png"))
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Item1',  },
    { label: '退出', role: 'quit'},
  ])
  tray.on("click", function (){
    if(mainWindow.visible){
      mainWindow.hide()
    }else {
      mainWindow.show()
    }
  })
  tray.setToolTip('This is my application.')
  tray.setContextMenu(contextMenu)
}

菜单和右键菜单

菜单

const menuList = {
    label: '文件',
    submenu: [
      {label: '文件', role: 'windowMenu', toolTip: 'all'},
      {role: 'reload'},
      {label: '最小化', role: 'minimize'},
      {role: 'zoom'},
      {label: '退出', role: 'quit'},
    ]
  },
  {
    label: '编辑',
    submenu: [
      {role: 'undo'},
      {role: 'redo'},
      {role: 'copy'},
      {role: 'paste'}
    ]
  },
  {
    label: '关于',
    submenu: [
      {
        label: 'DevTools',
        role: 'toggleDevTools'
      },
      {type: 'separator'},
      {
        role: 'about'
      },
      {
        role: 'help'
      },
      {
        label: 'services',
        role: 'services'
      },
    ]
  }

let mainMenu = Menu.buildFromTemplate(menuList);
Menu.setApplicationMenu(mainMenu);

自定义右键

let contextMenu = Menu.buildFromTemplate([
  {
    label: 'Item 1',
    click: function () {
      console.log(1111);
    }
  },
  {role: 'editMenu'}
]);
// 控制右键操作
 wc.on('context-menu', (e, params) => {
   // 显示
 });

程序崩溃处理

  const wc = mainWindow.webContents; 
  // 程序崩溃的处理
  wc.on( 'crashed', () => {
    setTimeout( () => {
      mainWindow.reload()
    }, 1000)
  })
  wc.on( 'render-process-gone', () => {
    setTimeout( () => {
      mainWindow.reload()
    }, 1000)
  })

系统弹窗提示

 // 打开选择文件夹的系统弹窗
  dialog.showOpenDialog({
    buttonLabel: 'Select a photo',
    defaultPath: app.getPath('desktop'),
    properties: ['multiSelections', 'createDirectory', 'openFile', 'openDirectory']
  }).then( result => {
    console.log(result)
  })

  // 打开另存为的系统弹窗
  dialog.showSaveDialog({}).then( result => {
    console.log(result)
  })

  // 系统错误弹窗
  dialog.showErrorBox(title, content)

  const answers = ['Yes', 'No', 'Maybe', 'today']

  dialog.showMessageBox({
    title: '下一步',
    message: '请选择安装模块',
    detail: '模块的具体使用方法',
    buttons: answers
  }).then( result => {
    console.log(`User selected: ${answers[result.response]}`)
  })

下载文件

// 页面
<a href="demo.png" download>Download Image</a></h2>

// 下载资源
session.defaultSession.on('will-download', (e, downloadItem, webContents) => {

  let fileName = downloadItem.getFilename();
  let fileSize = downloadItem.getTotalBytes();
  console.log('download');
  console.log(fileName);
  console.log(fileSize);
  // Save to desktop
  
  downloadItem.setSavePath(app.getPath('desktop') + `/${fileName}`);

  // downloadItem.on('updated', (e, state) => {
  //
  //   let received = downloadItem.getReceivedBytes()
  //
  //   if (state === 'progressing' && received) {
  //
  //     let progress = Math.round((received/fileSize)*100)
  //     webContents.executeJavaScript(`window.progress.value = ${progress}`)
  //   }
  // })
});

cookie

   let ses = session.defaultSession;

    let getCookies = () => {
      ses.cookies.get({name: 'cookie1'})
        .then(cookies => {
          console.log(cookies);
        })
        .catch(errors => {
          console.log(errors);
        });
    };

    let cookie = {url: 'https://myappdomain.com', name: 'cookie1', value: 'electron', expirationDate: 1622818789};

    ses.cookies.set(cookie)
      .then(() => {
        console.log('cookie1 set');
        getCookies();
      });

    mainWindow.webContents.on('did-finish-load', e => {
      getCookies();
    });

获取显示器数据

let displays = screen.getAllDisplays()

let primaryDisplay = screen.getPrimaryDisplay()

const screenConf = {
  x: primaryDisplay.bounds.x, y: primaryDisplay.bounds.y,
  width: primaryDisplay.size.width/2, height: primaryDisplay.size.height,
}

剪贴板

<br><button onclick="makeUpper()">Make clipboard uppercase</button>
<br><button onclick="showImage()">Show clipboard image</button>
<br><img src="" id="cbImage">

<script>
  const { clipboard } = require('electron')
  const showImage = e => {
    let image = clipboard.readImage()
    document.getElementById('cbImage').src = image.toDataURL()
  }
  const makeUpper = e => {
    let cbText = clipboard.readText()
    clipboard.writeText( cbText.toUpperCase() )
  }
  // 清空剪贴板
  clipboard.clear();
</script>

快捷键

// 添加快捷键
globalShortcut.register('CommandOrControl+G', () => {
   dialog.showMessageBox({
     title: '快键键',
     message: '快键键',
     detail: 'CommandOrControl+G',
   }).then( result => {
     console.log(`User selected:`)
   })

 })

// 删除快捷键
 globalShortcut.unregister('CommandOrControl+G')

通知

<script>
  setTimeout( () => {
    let notification = new Notification( 'Electron App', {
      body: 'Some notification info!'
    })
    notification.onclick = e => {
      console.log(1111)
    }
  }, 2000)
</script>

监听电源情况

  // 监视电源状态的改变。
  electron.powerMonitor.on('resume', e => {
    if(!mainWindow) createWindow()
  })

  electron.powerMonitor.on('suspend', e => {
    console.log('Saving some data')
  })


更多

github上的项目参考master-electron

node-gyp

GYP是一种构建自动化工具。node程序中需要调用一些其他语言编写的 工具 甚至是dll,需要先编译一下,否则就会有跨平台的问题,例如在windows上运行的软件copy到mac上就不能用了,但是如果源码支持,编译一下,在mac上还是可以用的。node-gyp在较新的Node版本中都是自带的(平台相关),用来编译原生C++模块。
使用node-gyp编写简单的node原生模块

快速开发模板

https://gitee.com/starbugs/electron-ts-react

你可能感兴趣的:(移动开发,electron,javascript,前端)