简体   繁体   English

如何创建具有多个部分的Electron应用程序

[英]How to create an Electron app with multiple sections

I'm trying to create an Electron app that has multiple "pages". 我正在尝试创建一个具有多个“页面”的Electron应用程序。

In my case, I'm trying to make an app with a sidebar that has different sections. 就我而言,我正在尝试制作一个带有不同部分的侧边栏的应用程序。 Once a section is clicked, the main window's content changes to render the appropriate content for the section. 单击某个部分后,主窗口的内容将更改为呈现该部分的适当内容。

I'm new to JS so sorry if this is a dumb question, but as of now, whenever I try to go to a section of the app, I get a white-flash screen for a second before everything loads again. 我是JS的新手,如果这是一个愚蠢的问题,对不起,但是截至目前,每当我尝试进入该应用程序的某个部分时,在所有内容再次加载之前,我都会获得一刹那白屏。

Example: https://i.imgur.com/qOyuYsz.gif 范例: https//i.imgur.com/qOyuYsz.gif

I know this has to do with Electron reloading the Chrome engine, but how can I make it so when a section is clicked, the content is displayed automatically without any "flashes" or weird things? 我知道这与Electron重新加载Chrome引擎有关,但是如何做到这一点,当单击某个部分时,内容会自动显示而不会出现“闪烁”或奇怪的现象?

Basically: how can I build a GUI with lots of components using Electron? 基本上:如何使用Electron构建包含许多组件的GUI?

My code for my index.html is: 我的index.html代码是:

 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Rupture Tools</title> <link rel="stylesheet" href="./photon/css/photon.min.css"> </head> <body> <div class="window"> <div class="window-content"> <div class="pane-group"> <div class="pane-sm sidebar"> <nav class="nav-group"> <h5 class="nav-group-title">1 Click Generator</h5> <a class="nav-group-item active"> <span class="icon icon-home"></span> Dashboard </a> <a href="accounts.html"> <span class="nav-group-item"> <span class="icon icon-user-add"></span> Accounts </span> </a> <span class="nav-group-item"> <span class="icon icon-cloud-thunder"></span> Activity </span> <span class="nav-group-item"> <span class="icon icon-check"></span> Check Scores </span> <span class="nav-group-item"> <span class="icon icon-cog"></span> Settings </span> <span class="nav-group-item"> <span class="icon icon-help-circled"></span> Help/FAQ </span> </nav> </div> <div class="pane">Home</div> </div> </div> </div> </body> </html> 

Please help! 请帮忙! I'm clueless at this, been searching everywhere. 我对此一无所知,一直到处搜寻。 I come from Python where there isn't much of any front-end development or GUI designing. 我来自Python,那里没有任何前端开发或GUI设计。 Thanks! 谢谢!

There is "sort of" a solution here, but it uses something called Sass and as far as I know using something like React or Angular is better. 这里有一种“解决方案”,但是它使用了一种称为Sass的解决方案,据我所知,使用诸如React或Angular之类的解决方案更好。 I've never used either of those. 我从未使用过任何一个。

I made some code a while back to do this (Unfortunately it's rather complicated but it shouldn't be so hard to implement it). 我花了一段时间编写了一些代码来完成此操作(不幸的是,它相当复杂,但是实现起来并不难)。

You put this function on every page: 您在每个页面上都放置了此功能:

function loadPageWithIframe (url) {
    var hiddenPage = document.createElement("iframe");
    hiddenPage.setAttribute("src", url);
    hiddenPage.style.display = 'none';
    document.body.appendChild(hiddenPage);
    hiddenPage.onload = function () {
        var frameDocument = hiddenPage.document;
        if (hiddenPage.contentDocument) {
            frameDocument = hiddenPage.contentDocument;
        } else if (hiddenPage.contentWindow) {
            frameDocument = hiddenPage.contentWindow.document;
        }
        document.open();
        document.write(frameDocument.documentElement.innerHTML);
        document.close();
        window.history.pushState("", document.title, url.replace('https://' + window.location.hostname, ''));
    }
}

And this code in your Electron file: 这段代码在您的Electron文件中:

mainWindow.webContents.on('will-navigate', function (evt, url) {
    evt.preventDefault();
    mainWindow.webContents.executeJavaScript('loadPageWithIframe("' + url + '");');
});

And if you put the code in correctly it should work automatically, without any extra code. 而且,如果您正确放置了代码,它应该会自动运行,而无需任何额外的代码。

The way this works is you call the loadPageWithIframe function when you want to go to a url, then it makes an iframe and loads the page, copies the all the html from the iframe and overwrites the current page's HTML with the iframes HTML. 这种方法的工作方式是,当您要转到url时调用loadPageWithIframe函数,然后创建一个iframe并加载页面,从iframe复制所有html,然后用iframe HTML覆盖当前页面的HTML。

But instead of calling the loadPageWithIframe function on manually on every click you can use Electron's will-navigate event to let us know that it's going to another page, then call the loadPageWithIframe (this is the purpose of the electron code that I posted). 但是,您不必使用每次单击都手动调用loadPageWithIframe函数的方法,而可以使用Electron的will-navigate事件让我们知道它正在转到另一页,然后调用loadPageWithIframe (这是我发布的电子代码的目的)。

I hope that Helps :) 希望对您有所帮助:)

Electron apps are very similar to web apps. 电子应用程序与网络应用程序非常相似。 The traditional way of navigating between HTML documents doesn't work well for apps as you noticed. 如您所见,在HTML文档之间进行导航的传统方式不适用于应用程序。 That's why web apps are developed as single-page applications (SPA) nowadays. 这就是为什么现在将Web应用程序开发为单页应用程序 (SPA)的原因。 It simply means loading and replacing parts of the page manually using JavaScript when the user navigates. 这只是意味着用户导航时使用JavaScript手动加载和替换页面的某些部分。 There are several ways to implement this, but here's an example how it could be done for your code: 有几种方法可以实现此目的,但是这里有一个示例如何为您的代码完成它:

// Get all the navigation links to an array
const naviLinks = Array.from(document.getElementsByClassName("nav-group-item"));
const contentEl = document.getElementsByClassName("pane")[0];

naviLinks.forEach((linkEl) => {
    // Listen click event for the navigation link
    linkEl.addEventListener("click", e => {
        // Prevent default behavior for the click-event
        e.preventDefault();
        // Get the path to page content file
        const href = linkEl.getAttribute("href");
        if (href) {
            // Use node.js fs-module to read the file
            const fs = require("fs");
            fs.readFile(href, (err, data) => {
                if (err) {
                    throw err;
                }
                // show the selected page
                contentEl.innerHTML = "";
                contentEl.insertAdjacentHTML("beforeend", data);
            })
        }
    })
})

Note that the page content HTML files (accounts.html etc.) should only have the content for the "pane" div . 请注意,页面内容HTML文件(accounts.html等)应仅包含“窗格” div You also need to pass nodeIntegration:true when creating your BrowserWindow -object in the main-process, so you can use require to load the fs -module: 在主进程中创建BrowserWindow时,还需要传递nodeIntegration:true ,因此可以使用require加载fs -module:

new BrowserWindow({
    webPreferences: {
        nodeIntegration: true
    }
}

If the page content files are large, navigation may seem slow, because files are read and pages are rendered on every click. 如果页面内容文件很大,则导航可能会变慢,因为每次单击都会读取文件并呈现页面。 One optimization to help with that is to read files and create page elements off-screen already at page load and then just swap the elements on click -events. 一种帮助解决此问题的优化方法是在页面加载时在屏幕外读取文件并创建页面元素,然后在click -events上交换元素。 Alternatively you could put the page contents in <template> -elements and swap them. 或者,您可以将页面内容放在<template> -elements中并交换它们。 I'll leave these for you to try out by yourself, if you're interested. 如果您有兴趣,我会把这些留给您自己尝试。

There are loads of JavaScript frameworks that can help you with creating SPAs. 有很多JavaScript框架可以帮助您创建SPA。 Some popular ones at the moment are React, Angular and Vue. 目前一些受欢迎的是React,Angular和Vue。 "How can I build a GUI with lots of components?" “如何构建具有许多组件的GUI?” is one of the questions front-end JavaScript frameworks can answer, but there's of course a learning curve. 是前端JavaScript框架可以回答的问题之一,但是当然还有学习的余地。 When you feel the need to start splitting your GUI into reusable or hierarchical components, it's probably a good idea to look into those JavaScript frameworks. 当您需要将GUI分为可重用或分层的组件时,考虑使用这些JavaScript框架可能是个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM