📜  使用 Electron 创建 GeeksforGeeks 包装应用程序

📅  最后修改于: 2022-05-13 01:56:28.543000             🧑  作者: Mango

使用 Electron 创建 GeeksforGeeks 包装应用程序

Electron是一个开源且独立于平台的框架,用于使用 Chromium 引擎和 Node.js 的强大功能创建本地桌面应用程序。

我们将使用 Electron 创建一个简单的应用程序,它充当 GeeksforGeeks 网站的包装器。它包含快速导航到网站重要部分的功能,在需要时单独打开“在线 IDE”并保存以后可以离线阅读的文章。

它利用了 Electron 框架的各种功能,包括浏览器窗口、本地菜单、文件处理和打包应用程序以进行分发。

先决条件:

  • 运行 Electron 应用程序需要Node.js 运行时。这包括像npm这样的工具来帮助构建和安装所需的包。在 Windows 上安装 Node.js。
  • 了解HTML、CSS 和 JavaScript
  • Electron和Node.js的入门知识

初始化一个新的 Node 项目:

  1. 导航到您希望创建项目的位置。打开命令提示符并使用以下命令初始化新项目:
    npm init
  2. 按照命令提示符窗口中的要求填写项目的详细信息。这将创建一个package.json文件,该文件指示将用于运行应用程序的所有库。
  3. 使用以下 npm 命令安装 Electron 包:
    npm install electron
  4. 打开package.json文件并将“scripts”部分更改为以下内容:
    "scripts": {
        "start": "electron ."
      }
    

    这使得通过 npm 实用程序运行我们的应用程序变得很容易。

    包-json

创建 Electron 基本结构:我们首先创建应用程序的基本结构。 index.js (或package.json中配置的相应文件)是 Electron 可执行文件尝试启动应用程序的入口点。我们将使用以下代码在index.js文件中定义应用程序结构:

  • 程序:
    const { app, BrowserWindow } = require('electron')
      
    // Global variable that holds the app window
    let win
      
    function createWindow() {
      
      // Creating the browser window
      win = new BrowserWindow({
        width: 960,
        height: 540,
      })
      
      // Load a redirecting url from
      // login to the feed
      win.loadURL(
    'https://auth.geeksforgeeks.org/?to=https://auth.geeksforgeeks.org/profile.php')
      
      win.on('closed', () => {
        win = null
      })
      
      // Prevent from spawning new windows
      win.webContents.on('new-window', (event, url) => {
      
        event.preventDefault()
        win.loadURL(url)
      })
    }
      
    // Executing the createWindow function
    // when the app is ready
    app.on('ready', createWindow)
    
  • 该应用程序可以使用以下命令运行:
    npm start
  • 输出:

解释:

  • 我们已经定义了一个带有窗口尺寸的BrowserWindow ,并使用loadURL()方法加载了网站的登录页面。 BrowserWindow 就像嵌入在我们的应用程序中的浏览器,可用于浏览网页。
  • 每当运行此应用程序时,它都会创建 BrowserWindow 的一个实例并将指定的 URL 加载到窗口中。

创建菜单: Electron 应用程序具有创建菜单项的功能,这些菜单项将本机显示在应用程序的菜单栏中。这些可以链接到单击它们时将发生的操作。

菜单最初是从一个模板创建的,该模板定义了每个菜单和子菜单的显示方式以及它们的作用。我们的菜单有 6 个部分:

  • 文件:它可以选择保存当前页面并退出应用程序。
  • 站点:它具有登录和注销网站的选项。
  • 学习:它可以选择已撰写文章的网站的各个部分。
  • 练习题:它可以选择在单独的窗口中打开在线IDE,也可以根据难度直接进入问题。
  • 贡献:它具有与文章对网站的贡献相对应的各种选项。
  • 已保存的文章:它允许访问以前已保存的所有文章。

所有 URL 均直接来自 GeekforGeeks 网站。 “保存的页面”部分留空,以便以后更新。通过创建 BrowserWindow 的新实例并在其中加载 URL,将为在线 IDE 创建一个单独的窗口。

最终模板菜单代码如下:

  • 程序:
    let menu_template = [
      {
        label: 'File',
        submenu: [
          {
            label: 'Save Page Offline',
            click() {
              savePageOffline()
            }
          },
          { type: 'separator' },
          {
            label: 'Exit',
            click() {
              app.quit()
            }
          }
        ]
      },
      {
        label: 'Site',
        submenu: [
          {
            label: 'Login',
            click() {
              win.loadURL(
    "https://auth.geeksforgeeks.org")
            }
          },
          {
            label: 'Logout',
            click() {
              win.loadURL(
    "https://auth.geeksforgeeks.org/logout.php")
            }
          },
        ]
      },
      {
        label: 'Learn',
        submenu: [
          {
            label: 'Quiz Corner',
            click() {
              win.loadURL(
    "https://www.geeksforgeeks.org/quiz-corner-gq/")
            }
          },
          {
            label: 'Last Minute Notes',
            click() {
              win.loadURL(
    "https://www.geeksforgeeks.org/lmns-gq/")
            }
          },
          {
            label: 'Interview Experiences',
            click() {
              win.loadURL(
    "https://www.geeksforgeeks.org/company-interview-corner/")
            }
          },
          {
            label: 'Must-Do Questions',
            click() {
              win.loadURL(
    "https://www.geeksforgeeks.org/must-do-coding-questions-for-companies-like-amazon-microsoft-adobe/")
            }
          }
        ]
      },
      {
        label: 'Practice Questions',
        submenu: [
          {
            label: 'Online IDE',
            click() {
      
              // Creating new browser window for IDE
              ide_win = new BrowserWindow({
                width: 800,
                height: 450,
              })
      
              ide_win.loadURL(
    "https://ide.geeksforgeeks.org")
      
              // Delete this window when closed
              ide_win.on('closed', () => {
                ide_win = null
              })
            }
          },
          { type: 'separator' },
          {
            label: 'Easy Questions',
            click() {
              win.loadURL(
    "https://practice.geeksforgeeks.org/explore/?difficulty[]=0&page=1")
            }
          },
          {
            label: 'Medium Questions',
            click() {
              win.loadURL(
    "https://practice.geeksforgeeks.org/explore/?difficulty[]=1&page=1")
            }
          },
          {
            label: 'Hard Questions',
            click() {
              win.loadURL(
    "https://practice.geeksforgeeks.org/explore/?difficulty[]=2&page=1")
            }
          },
          { type: 'separator' },
          {
            label: 'Latest Questions',
            click() {
              win.loadURL(
    "https://practice.geeksforgeeks.org/recent.php")
            }
          }
        ]
      },
      {
        label: 'Contribute',
        submenu: [
          {
            label: 'Write New Article',
            click() {
              win.loadURL(
    "https://contribute.geeksforgeeks.org/wp-admin/post-new.php")
            }
          },
          {
            label: 'Pick Suggested Article',
            click() {
              win.loadURL(
    "https://contribute.geeksforgeeks.org/request-article/request-article.php#pickArticleDiv")
            }
          },
          {
            label: 'Write Interview Experience',
            click() {
              win.loadURL(
    "https://contribute.geeksforgeeks.org/wp-admin/post-new.php?interview_experience")
            }
          }
        ]
      },
      {
        id: 'saved',
        label: 'Saved Articles',
        submenu: []
      }
    ]
    

    解释:

    • 我们将首先导入MenuMenuItem命名空间。这些包含我们将要使用的方法的定义。
    • label属性定义了每个项目的文本。 submenu属性指定单击 MenuItem 时将打开的子菜单项数组。
    • 在每个标签之后,可以定义单击子菜单时将发生的操作。例如,我们将使用loadURL()方法加载网站的其他部分。每当用户单击子菜单时,它将执行此方法并加载网站的新部分。
    • 定义了一个变量,它保存将从模板构建的菜单。 Menu命名空间具有buildFromTemplate()setApplicationMenu()方法,可以在我们的应用程序中使用创建的菜单。
      // Build the template and use the menu
      const menu = Menu.buildFromTemplate(menu_template)
      Menu.setApplicationMenu(menu)
    菜单

    菜单栏和子菜单

    online_ide

    单独窗口中的在线 IDE

    添加保存页面的功能:我们现在将添加将页面保存到磁盘的功能,以便以后即使没有互联网连接也可以访问它。我们将首先定义我们的文章将被存储的位置。我们可以获取当前工作目录并为保存的页面创建一个文件夹。

    const savedFolder = __dirname + '\\saved\\'

    三个函数共同作用来保存和检索文章:

    appendItemToMenu(filename)函数:

    • 该函数将给定的页面标题添加到“保存的页面”子菜单中,并将其链接起来,以便在用户单击它们时加载页面。
    • 使用getApplicationMenu()方法检索当前活动的菜单。
    • 然后它使用append()方法添加一个新的 MenuItem。此 MenuItem 构造函数被赋予将显示为标签的文件名以及单击它时将发生的功能。
    • 它会自动更新当前菜单,最新的页面可以立即使用。
    • 代码:
      function appendItemToMenu(filename) {
        curr_menu = Menu.getApplicationMenu()
              .getMenuItemById("saved").submenu
        
        curr_menu.append(
          new MenuItem({
            label: path.basename(filename, '.html'),
            click() {
              console.log('Saved page opened')
              win.loadFile(savedFolder + path.basename(filename))
            }
          }))
      }
      

    savePageOffline()函数:

    • 此函数将整个页面连同所有图像和样式表一起保存到磁盘。
    • 文件名是使用getTitle()方法确定的,该方法返回当前页面的标题。
    • contents.savePage()方法将获取当前网页并将其保存到具有上述标题的给定位置。
    • 它还调用上面的appendItemToMenu()来更新菜单。
    • 代码:
      function savePageOffline() {
        pageTitle = win.getTitle()
        console.log("Saving:", pageTitle)
        
        win.webContents.savePage(savedFolder + pageTitle + 
                      '.html', 'HTMLComplete').then(() => {
          appendItemToMenu(pageTitle + '.html');
          console.log('Page was saved successfully.')
        }).catch(err => {
          console.log(err)
        })
      }
      

    getSavedArticles()函数:

    • 此函数检索给定文件夹中的所有文件,然后将它们添加到菜单中。
    • 它使用readdirSync()方法返回“已保存”文件目录中存在的所有文件名。
    • 检查文件名,以便只考虑扩展名为“.html”的文件名。
    • 然后将它们传递给appendItemToMenu()函数,以便为每个保存的项目更新菜单。
    • 代码:
      function getSavedArticles() {
        fs.readdirSync(savedFolder).forEach(file => {
          if (path.extname(file) == '.html') {
            appendItemToMenu(file)
          }
        });
      }
      

    savePageOffline()函数是从“文件”菜单中的“离线保存页面”调用的。在创建 BrowserWindow 期间调用getSavedArticles()函数,以便之前的页面立即可用。每当保存新页面时都会调用appendItemToMenu()函数。这允许无缝保存和检索可以离线阅读的文章。

    保存页面之前

    保存页面和检索保存的页面

    打包应用程序:由于 Electron 是一个独立于平台的框架,应用程序可以使用单个代码库在所有主要平台上运行。 Electron 社区已经创建了一个包,它为各种支持的平台捆绑了一个完成的应用程序,并使其准备好分发。

  • 可以使用以下命令全局安装 electron-packager 工具以在 CLI 中使用:
    npm install electron-packager -g
  • 电子打包器具有以下语法:
    electron-packager 
         
            --platform= 
           --arch= [optional flags...]
  • 如果正在为某个平台开发,则可以指定“平台”和“架构”。运行仅指定“sourcedir”和“appname”的打包程序将生成一个只能在主机平台/架构上运行的包:
    electron-packager . geeksforgeeks-desktop
    电子包装器

    电子包装器

    打包应用

    windows平台的最终打包应用程序

    进一步阅读:我们已经介绍了一个非常基本的应用程序,它展示了 Electron 的一些特性。该框架具有更多功能,可以集成在一起以构建更复杂的应用程序。建议通过以下链接进一步阅读:

    • 官方电子文档
    • 使用 Electron 构建的应用程序集合:电子应用程序
    • 此应用程序的参考代码:geeksforgeeks-desktop