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.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();
}
});
// 控制右键操作
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');
});
简单通信
// 页面上点了按钮
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
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>
<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>
<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}`)
// }
// })
});
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
GYP是一种构建自动化工具。node程序中需要调用一些其他语言编写的 工具 甚至是dll,需要先编译一下,否则就会有跨平台的问题,例如在windows上运行的软件copy到mac上就不能用了,但是如果源码支持,编译一下,在mac上还是可以用的。node-gyp在较新的Node版本中都是自带的(平台相关),用来编译原生C++模块。
使用node-gyp编写简单的node原生模块
https://gitee.com/starbugs/electron-ts-react