09.《Electron 跨平台开发实战》- chapter09-tray模块

项目代码

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'))
posted @ 2020-06-17 16:40  easy5  阅读(415)  评论(0编辑  收藏  举报