zoukankan      html  css  js  c++  java
  • 10.《Electron 跨平台开发实战》- chapter10-menubar

    项目代码

    https://github.com/electron-in-action/clipmaster-9000/tree/completed-example

    代码解析

    electron9.x 代码更新

    从源码下载的使用目前最新的版本 electron9.x、menubar 9.x ,
    无法运行,原因是

    1. 无法识别Menubar类
    2. 得显式的让browserWindow集成node环境

    需要做如下修改:

    • main.js
    • 旧版本的代码
    const Menubar = require('menubar');
    const { globalShortcut, Menu } = require('electron');
    
    const menubar = Menubar({
      preloadWindow: true,
      index: `file://${__dirname}/index.html`,
    });
    
    
    • electron9.x版本 修改为
    const { menubar } = require('menubar');
    const { globalShortcut, Menu } = require('electron');
    
    const mb = menubar({
      preloadWindow: true,
      browserWindow: {
        webPreferences: {
          nodeIntegration: true
        }
      },
      index: `file://${__dirname}/index.html`,
    });
    
    

    request 代码要修改

    旧版本代码

    const publishClipping = (clippingText) => {
      request.post(toJSON(clippingText), (err, response, body) => {
      ... 
        const gistUrl = JSON.parse(body).html_url;
      ... 
      });
    };
    
    

    API接口可能已经修改,返回值估计也有变化,这里取body.documentation_ur作为跳转页面,打开默认浏览器
    修改为:

    let baseUrl = 'https://api.github.com/gists';
    ...
    const publishClipping = (clippingText) => {
    
      request.post(baseUrl, toJSON(clippingText), (err, response, body) => {
     ...
        const gistUrl = JSON.parse(body).documentation_url; //   const gistUrl = JSON.parse(body).html_url;
    ...
      });
    
    };
    

    完整代码

    index.html

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <title>Clipmaster 9000</title>
      <link rel="stylesheet" href="style.css" type="text/css">
    </head>
    
    <body>
      <div class="container">
        <section class="controls">
          <button id="copy-from-clipboard">Copy from Clipboard</button>
        </section>
    
        <section class="content">
          <div id="clippings-list" class="clippings-list"></div>
        </section>
      </div>
      <script>
        require('./renderer.js');
      </script>
    </body>
    
    </html>
    
    

    main.js

    const { menubar } = require('menubar');
    const { globalShortcut, Menu } = require('electron');
    
    const mb = menubar({
      preloadWindow: true,
      browserWindow: {
        webPreferences: {
          nodeIntegration: true
        }
      },
      index: `file://${__dirname}/index.html`,
    });
    
    
    mb.on('ready', () => {
      const secondaryMenu = Menu.buildFromTemplate([
        {
          label: 'Quit',
          click() { mb.app.quit(); },
          accelerator: 'CommandOrControl+Q'
        },
      ]);
    
      mb.tray.on('right-click', () => {
        mb.tray.popUpContextMenu(secondaryMenu);
      });
    
      const createClipping = globalShortcut.register('CommandOrControl+!', () => {
        mb.window.webContents.send('create-new-clipping');
      });
    
      const writeClipping = globalShortcut.register('CmdOrCtrl+Alt+@', () => {
        mb.window.webContents.send('write-to-clipboard');
      });
    
      const publishClipping = globalShortcut.register('CmdOrCtrl+Alt+#', () => {
        mb.window.webContents.send('publish-clipping');
      });
    
      if (!createClipping) { console.error('Registration failed', 'createClipping'); }
      if (!writeClipping) { console.error('Registration failed', 'writeClipping'); }
      if (!publishClipping) { console.error('Registration failed', 'publishClipping'); }
    });
    
    

    renderer.js

    const { clipboard, ipcRenderer, shell } = require('electron');
    let baseUrl = 'https://api.github.com/gists';
    
    const request = require('request').defaults({
      url: baseUrl,
      headers: { 'User-Agent': 'Clipmaster 9000' }
    });
    
    const clippingsList = document.getElementById('clippings-list');
    const copyFromClipboardButton = document.getElementById('copy-from-clipboard');
    
    ipcRenderer.on('create-new-clipping', () => {
      addClippingToList();
      new Notification('Clipping Added', {
        body: `${clipboard.readText()}`
      });
    });
    
    ipcRenderer.on('write-to-clipboard', () => {
      const clipping = clippingsList.firstChild;
      writeToClipboard(getClippingText(clipping));
      new Notification('Clipping Copied', {
        body: `${clipboard.readText()}`
      });
    });
    
    ipcRenderer.on('publish-clipping', () => {
      const clipping = clippingsList.firstChild;
      publishClipping(getClippingText(clipping));
    });
    
    const createClippingElement = (clippingText) => {
      const clippingElement = document.createElement('article');
    
      clippingElement.classList.add('clippings-list-item');
    
      clippingElement.innerHTML = `
        <div class="clipping-text" disabled="true"></div>
        <div class="clipping-controls">
          <button class="copy-clipping">&rarr; Clipboard</button>
          <button class="publish-clipping">Publish</button>
          <button class="remove-clipping">Remove</button>
        </div>
      `;
    
      clippingElement.querySelector('.clipping-text').innerText = clippingText;
    
      return clippingElement;
    };
    
    const addClippingToList = () => {
      const clippingText = clipboard.readText();
      const clippingElement = createClippingElement(clippingText);
      clippingsList.prepend(clippingElement);
    };
    
    copyFromClipboardButton.addEventListener('click', addClippingToList);
    
    clippingsList.addEventListener('click', (event) => {
      const hasClass = className => event.target.classList.contains(className);
    
      const clippingListItem = getButtonParent(event);
    
      if (hasClass('remove-clipping')) removeClipping(clippingListItem);
      if (hasClass('copy-clipping')) writeToClipboard(getClippingText(clippingListItem));
      if (hasClass('publish-clipping')) publishClipping(getClippingText(clippingListItem));
    });
    
    const removeClipping = (target) => {
      target.remove();
    };
    
    const writeToClipboard = (clippingText) => {
      clipboard.writeText(clippingText);
    };
    
    const publishClipping = (clippingText) => {
    
      request.post(baseUrl, toJSON(clippingText), (err, response, body) => {
    
        if (err) {
          return new Notification('Error Publishing Your Clipping', {
            body: JSON.parse(err).message
          });
        }
    
        const gistUrl = JSON.parse(body).documentation_url; //   const gistUrl = JSON.parse(body).html_url;
        const notification = new Notification('Your Clipping Has Been Published', {
          body: `Click to open ${gistUrl} in your browser.`
        });
    
        notification.onclick = () => { shell.openExternal(gistUrl); };
    
        clipboard.writeText(gistUrl);
      });
    
    };
    
    const getButtonParent = ({ target }) => {
      return target.parentNode.parentNode;
    };
    
    const getClippingText = (clippingListItem) => {
      return clippingListItem.querySelector('.clipping-text').innerText;
    };
    
    const toJSON = (clippingText) => {
      return {
        body: JSON.stringify({
          description: 'Created with Clipmaster 9000',
          public: 'true',
          files: {
            'clipping.txt': { content: clippingText }
          }
        })
      };
    };
    
    
    

    style.css

    html {
      box-sizing: border-box;
    }
    
    html, body {
      height: 100%;
       100%;
      overflow: hidden;
      font-size: 12px;
    }
    
    *, *:before, *:after {
      box-sizing: inherit;
    }
    
    body {
      margin: 0;
      padding: 0;
    }
    
    body, input {
      font: menu;
      font-size: 12px;
    }
    
    body > div {
      height: 100%;
      overflow: scroll;
      -webkit-overflow-scrolling: touch;
    }
    
    .container {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      overflow: auto;
    }
    
    textarea, input, div, button { outline: none; }
    
    .controls {
      background-color: rgb(217, 241, 238);
      padding: 1em;
      top: 0;
      position: fixed;
       100%;
    }
    
    .controls button {
      background-color: rgb(181, 220, 216);
      border: none;
      padding: 0.5em 1em;
    }
    
    .controls button:hover {
      background-color: rgb(156, 198, 192);
    }
    
    .controls button:active {
      background-color: rgb(144, 182, 177);
    }
    
    .controls button:disabled {
      background-color: rgb(196, 204, 202);
    }
    
    .content {
      height: 100%;
    }
    
    .clippings-list {
      margin-top: 65px;
      padding: 0 10px;
    }
    
    .clippings-list-item {
      border: 1px solid rgb(178, 193, 191);
      box-shadow: 1px 1px 1px 1px rgba(205, 228, 224, 0.78);
      padding: 0.5em;
      margin-bottom: 1em;
    }
    
    .clipping-text {
      background-color: rgb(228, 248, 245);
      padding: 0.5em;
      min- 100%;
      max-height: 10em;
      overflow: scroll;
    }
    
    .clipping-text::-webkit-scrollbar {
      display: none;
    }
    
    .clipping-controls {
      margin-top: 0.5em;
    }
    
    button {
      background-color: rgb(181, 220, 216);
      border: none;
      font-size: 0.8em;
      padding: 0.5em 1em;
    }
    
    button:hover {
      background-color: rgb(156, 198, 192);
    }
    
    button:active {
      background-color: rgb(144, 182, 177);
    }
    
    button:disabled {
      background-color: rgb(196, 204, 202);
    }
    
    button.remove-clipping {
      display: none;
      float: right;
      color: white;
      background-color: rgb(208, 69, 55);
    }
    
    button.remove-clipping:hover {
      background-color: rgb(208, 41, 29);
    }
    
    button.remove-clipping:active {
      background-color: rgb(236, 0, 6);
    }
    
    button.remove-clipping:disabled {
      background-color: rgb(152, 73, 64);
    }
    
    .clippings-list-item:hover button.remove-clipping {
      display: inline-block;
    }
    
    

    package.json

    {
      "name": "clipmaster-9000",
      "version": "1.0.0",
      "description": "A menubar application with a rich UI.",
      "main": "app/main.js",
      "scripts": {
        "start": "electron .",
        "test": "echo "Error:no test specified" && exit 1"
      },
      "author": "weikai",
      "license": "MIT",
      "dependencies": {
        "electron": "^9.0.3",
        "menubar": "^9.0.1",
        "request": "^2.88.2"
      }
    }
    
  • 相关阅读:
    nginx主配置文件详解
    微信网页第三方登录原理
    QQ第三方登陆流程详解
    php垃圾回收机制
    mysql索引
    MySQL性能优化的最佳20+条经验
    MYSQL explain详解
    mysql分区功能详细介绍,以及实例
    MySQL分表、分区
    Redis主从读写分离配置
  • 原文地址:https://www.cnblogs.com/easy5weikai/p/13159423.html
Copyright © 2011-2022 走看看