目录
- 项目代码
- 创建Tray
- 为maxOS和window 选择不同的图标
- 将剪切项放入内存
- 要点解析
- const { ..., clipboard } = require('electron'); //剪切板模块
- 读取剪切项 const clipping = clipboard.readText();
- 写入剪切板 clipboard.writeText(clipping);
- js 3个点:扩展运算符
- 处理极端项(文字太长):clipping.length > 20 ? clipping.slice(0, 20) + '…' : clipping
- 避免添加重复的剪贴项: if (clippings.includes(clipping)) return;
- 最新在最前:clippings.unshift(clipping);
- 只显示10项:clippings.slice(0, 10).map(createClippingMenuItem)
- 要点解析
- 注册全局快捷
- 通知
- macOS单击菜单栏切换图标
项目代码
https://github.com/electron-in-action/clipmaster
创建Tray
- main.js
const path = require('path');
const { app, Menu, Tray } = require('electron');
let tray = null;
app.on('ready', () => {
tray = new Tray(path.join(__dirname, 'Icon.png'));
if (process.platform === 'win32') { //windows系统
tray.on('click', tray.popUpContextMenu);
}
if (app.dock) { //macOS系统
app.dock.hide(); //隐藏Dock图标
}
const menu = Menu.buildFromTemplate([
{
label: '退出',
// click() {
// app.quit();
// }
click: () => {
app.quit();
}
}
]);
tray.setToolTip('Clipmaster');
tray.setContextMenu(menu);
});
要点解析
tary基本设置
tray = new Tray(path.join(__dirname, 'Icon.png'));
tray.setToolTip('Clipmaster');
tray.setContextMenu(menu);
为maxOS和window 选择不同的图标
const getIcon = () => {
// if (process.platform === 'win32') {
// return 'icon-light@2x.ico';
// }
if (systemPreferences.isDarkMode()) { //maxOS系统是否处于深色模式
return 'icon-light@2x.png';
}
return 'icon-dark.png';
};
...
tray = new Tray(path.join(__dirname, getIcon()));
将剪切项放入内存
const { ..., clipboard } = require('electron'); //剪切板模块
app.on('ready', () => {
updateMenu();//tray.setContextMenu(menu);
});
const updateMenu = () => {
const menu = Menu.buildFromTemplate([
{
label: 'Create New Clipping',
click() { addClipping(); },
accelerator: 'CommandOrControl+Shift+C'
},
{ type: 'separator' },
...clippings.slice(0, 10).map(createClippingMenuItem),
{ type: 'separator' },
{
label: 'Quit',
click() { app.quit(); },
accelerator: 'CommandOrControl+Q'
}
]);
tray.setContextMenu(menu);
}
const addClipping = () => {
const clipping = clipboard.readText(); //读取剪切项
if (clippings.includes(clipping)) return;
clippings.unshift(clipping);
updateMenu();
return clipping;
};
const createClippingMenuItem = (clipping, index) => {
return {
label: clipping.length > 20 ? clipping.slice(0, 20) + '…' : clipping,
click() { clipboard.writeText(clipping); }, // 写入剪切板
accelerator: `CommandOrControl+${index}` //快捷键 递增
};
};
要点解析
const { ..., clipboard } = require('electron'); //剪切板模块
读取剪切项 const clipping = clipboard.readText();
写入剪切板 clipboard.writeText(clipping);
js 3个点:扩展运算符
var number = [1,2,3,4,5,6]
console.log(...number) //1 2 3 4 5 6
http://www.fly63.com/article/detial/8155
处理极端项(文字太长):clipping.length > 20 ? clipping.slice(0, 20) + '…' : clipping
避免添加重复的剪贴项: if (clippings.includes(clipping)) return;
最新在最前:clippings.unshift(clipping);
只显示10项:clippings.slice(0, 10).map(createClippingMenuItem)
注册全局快捷
accelerator: 'xxx
只有应用处于激活状态才能使用
globalShortcut 模块
globalShortcut 模块 提供注册全局快捷键的功能,即使应用处于后台,也能响应快捷键
注册全局快捷键: globalShortcut.register('xxx', () => { ...});
- main.js
app.on('ready', () => {
...
//注册全局快捷键:弹出菜单
const activationShortcut = globalShortcut.register('CommandOrControl+Alt+C', () => {
tray.popUpContextMenu();
});
if (!activationShortcut) console.error('Global activation shortcut failed to regiester');
//注册全局快捷键:将剪贴项放入内存数组
const newClippingShortcut = globalShortcut.register('CommandOrControl+Shift+Alt+C', () => {
const clipping = addClipping();
});
if (!newClippingShortcut) console.error('Global new clipping shortcut failed to regiester');
...
通知
使用 Chorminum的Notification API 创建通知
这种方案使用Chorminum的Notification API 创建通知, 是webAPI,所以只能在渲染进程中使用
- 创建一个隐藏不显示的BrowseWindow
- 主进程给消息给渲染进程创建通知
代码:
- 创建一个隐藏的BrowserWindow
index.htm:这个HTML文件唯一的目的就是为了加载渲染进程
<!DOCTYPE html>
<html>
<header>
<meta charset="UTF-8">
<title>Clipmaster</title>
</header>
<body>
</body>
<script>
//这个HTML文件唯一的目的就是为了加载渲染进程
require('./renderer.js');
</script>
</html>
- main.js
app.on('ready', () => {
...
browserWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true
},
show: false
});
browserWindow.loadURL(`file://${__dirname}/index.html`);
...
//注册全局快捷键:将剪贴项放入内存数组
const newClippingShortcut = globalShortcut.register('CommandOrControl+Alt+num8', () => {
const clipping = addClipping();
if (clipping) {
//向渲染进程发送消息,让渲染进程创建通知
browserWindow.webContents.send('show-notification', '已经添加到剪切板', clipping);
}
});
- renderer.js
const { ipcRenderer } = require('electron');
ipcRenderer.on('show-notification', (event, title, body) => {
const myNotification = new Notification(title, { body: body });
myNotification.onclick = () => { //点击通知触发click事件
alert("我知道了");
}
});
使用 Electron 的Notification 模块
主进程也可以向系统发通知
- main.js
const {
..., Notification // 通知模块
} = require('electron');
const updateMenu = () => {
const menu = Menu.buildFromTemplate([
{
label: 'Create New Clipping',
//click() { addClipping(); },
click: () => {
let clipping = addClipping();
//使用Notification模块发送通知
let myNotification = new Notification({
title: 'Notification模块通知',
body: clipping
})
myNotification.show();//必须调用show才会显示通知
myNotification.on('click', () => {
console.log('Notification模块通知的点击事件')
});
},
...
macOS单击菜单栏切换图标
//macOS单击菜单栏切换图标
tray.setPressedImage(path.join(__dirname, 'icon-light.png'))