Electron Saga3ï¶:所有开端都结束了。
#javascript #showdev #写作 #electron

我们回到了电子鼠尾草的最新部分。由于本系列更多地是关于设置的,所以我只会走这么远,因为构建应用程序本身并没有真正与Electron的工作相链接。

构架?

当我刚开始使用电子时,我没有考虑使用JavaScript框架。在大多数情况下,我将PHP用于我的网络开发,因此并没有想到这样的框架可能很有用。

我想构建的应用程序还可以做更多的事情,而不仅仅是将项目添加到我可以编辑的列表中。它需要扩展;因此,我用一个不错的侧边栏和一个主栏构建了第一页...并意识到每次添加新页面时都需要复制侧边栏。
使用PHP时,您将构建页面 index.php ,该页面包含侧栏和一个空的主体,该主栏将填充有require-或include函数。您将包含哪些文件取决于当前位置(URI)。

<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">

   <title>My Site</title>
</head>

<body>
    <header>
        <h1>Hello World</h1>
    </header>

    <aside>
        <nav>
            <ul>
                <li>navitem</li>
                <li>navitem</li>
                <li>navitem</li>
                <li>navitem</li>
            </ul>
        </nav>
    </aside>

    <main>
        <?include 'path_of_file'?>
    </main>
</body>

</html>

但没有php,所以没有html-cinclude。
我耸了耸肩,而不是寻找可以帮助我的NPM软件包,或者寻找像Svelte这样的框架;我决定尝试使用Vanilla JavaScript进口。它有效,有点。

布局

首先在/front/logic 和一个新文件 app.js 中创建一个新文件夹
然后将 app.js 文件链接为模块。

/front/index.html

<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>My App</title>
    <link rel="stylesheet" href="styles/reset.css">
    <link rel="stylesheet" href="styles/main.css">

    <!-- right here  -->
    <script type="module" src="logic/app.js"></script>
</head>

很棒,检查连接是否在上次记录值来检查:

/front/logic/app.js

console.log(E_system.mode);
console.log(E_system.platform);

没有破裂?太好了,让我们看看,我们希望它能起作用吗?
好吧,当我单击导航中的一个按钮时;内容应切换出来。
我希望能够分别将内容包含在标题,主和页脚中,以免打破我的主布局。因此,让我们建立一个导航,并在我们的体内包含一些插槽

/front/index.html

<body>
    <nav id="feature-nav" class="c-wrapper">
        <ul>
            <li>
                <button sheet="home">
                    <span>Home</span>
                </button>
            </li>
            <li>
                <button sheet="todo">
                    <span>Todo</span>
                </button>
            </li>
            <li>
                <button sheet="tracker">
                    <span>Schema</span>
                </button>
            </li>
        </ul>
    </nav>
    <div id="app-interface">
        <header>
            <content-slot></content-slot>
        </header>
        <main>
            <content-slot></content-slot>
        </main>
        <footer>
            <content-slot></content-slot>
        </footer>
    </div>
</body>

您可以看到我在所有按钮中添加了我称为sheet的属性。我还创建了一个文件夹/front/shay ,并添加了一些html文件,名称与这些属性值相对应。

当然,可以将aria标签添加到按钮中。或在ul上方添加一个跳过的按钮,但是这些功能在此检查系列中有点超出范围。

我希望床单是普通的旧html文件;我想要三个可以用JS Dom-Api来定位的容器,然后像通常一样编写内容。

/front/sheets/home.html

<header-content>
    <h1>Home</h1>
</header-content>

<main-content>
    my content
</main-content>

<footer-content>
    my footer
</footer-content>

JS

类称为page_loader,只是被导入并调用。 is_ready方法检查我们的index.html是否具有所有需要工作的元素; activate()方法启用按钮单击。

import { D$ } from "./fn/dev.js";
import { page_loader } from "./classes/loader.js";

console.log(E_system.mode);
console.log(E_system.platform);

//? Load Pager
{
    const page = new page_loader();
    if (page.is_ready()) {
        D$(console.log, "Page Loader Ready");
        page.activate();
    } else D$(console.warn, "Page Loader not Ready");
}

它通过使用fetch-api和domparser对象来工作。
单击按钮时,课程检查其链接到哪个表并获取文件。
返回纯文本串;传递给Domparser。此JS-Object能够将我们的普通字符串转换为HTML。
然后,我们使用良好的旧dom-api查询我们的内容障碍
<header-content> <main-content> <footer-content>
最后,这只是从我们的index.html中删除旧内容并粘贴新内容以获得我们的最终结果的问题。

辅助功能;

我做了一些助手功能,并将它们保存在文件/front/logic/fn/dev.js /em>和/front/logic/fn/fn/dom.js.js.js 。

$D()
:是仅当应用程序正在开发时才能启动通过函数的函数。它使用之前桥接的is_dev变量。

$S()
:QuerySelector的缩写

$SA()
:querySelectorall的缩写

Page_loader类

首先;更多的助手功能;这些完成了大部分工作;他们获取并转换数据。
我们也导入了前面提到的帮助者。

/front/logic/classes/loader.js

import { D$ } from "../fn/dev.js";
import { S$, SA$ } from "../fn/dom.js";

/**
 * @description get the sheet-attribute off of buttons
 * @param {HTMLButtonElement} _btn
 * @returns {string} - Sheet
 */
const get_sheet = (_btn) => {
    return _btn.getAttribute("sheet") || "";
};

/**
 * @description fetch sheet and return its data
 * @param {string} _sheet
 * @returns {response} - string
 */
async function find_sheet(_sheet) {
    const path = `./sheets/${_sheet}.html`;
    const F = await fetch(path, {
        method: "GET",
    })
        .then((response) => {
            // D$(console.log, response);
            return response.text();
        })
        .then((data) => {
            return data;
        })
        .catch((error) => {
            D$(console.log, error);
            return "";
        });
    return F;
}

/**
 * @description convert string to html of header-main-footer
 * @param {*} _html
 * @returns {array} - object of header_data, main_data, footer_data
 */
const data_to_html = (_html) => {
    var parser = new DOMParser();
    var doc = parser.parseFromString(_html, "text/html");
    const header_data = S$("header-content", doc)?.innerHTML.trim() || "";
    const main_data = S$("main-content", doc)?.innerHTML.trim() || "";
    const footer_data = S$("footer-content", doc)?.innerHTML.trim() || "";
    return [header_data, main_data, footer_data];
};

和主类;它只能使用sheets属性和<content-slot>标签查询所有NAV-BUTTON,并将单击事件附加到那些Nav-Buttons。
您可以添加更多功能。例如,在启动时自动加载home.html表。或最后使用的表格。
以及一些导航功能,例如显示当前表是什么。

export class page_loader {
    #header_slot;
    #main_slot;
    #footer_slot;

    #all_nav_btns;

    constructor() {
        this.#get_targets();
        this.#get_nav();
    }

    // query native elements
    #get_targets() {
        this.#header_slot = S$("#app-header content-slot");
        this.#main_slot = S$("#app-content content-slot");
        this.#footer_slot = S$("#app-footer content-slot");
    }
    #get_nav() {
        this.#all_nav_btns = SA$("#feature-nav [sheet]");
    }

    /**
     * Fetch given sheet and render the data in the app
     * @param {string} _sheet - sheet of data to fetch
     * @param {HTMLButtonElement} _btn - button to turn on in the nav
     * @returns {void}
     */
    async #render(_sheet, _btn) {
        const data = await find_sheet(_sheet);
        if (!data) return;
        const [header_data, main_data, footer_data] = data_to_html(data);

        this.#header_slot.innerHTML = header_data;
        this.#main_slot.innerHTML = main_data;
        this.#footer_slot.innerHTML = footer_data;
    }

    /**
     * @description checks to see if the loader has succesfully retrieved all nav btns and the content slots
     * @returns {boolean}
     */
    is_ready() {
        if (
            this.#all_nav_btns &&
            this.#header_slot &&
            this.#main_slot &&
            this.#footer_slot
        )
            return true;
        return false;
    }

    /**
     * @description function to activate click events on nav-btns
     */
    activate() {
        this.#all_nav_btns.forEach((btn) => {
            btn.addEventListener("click", (e) => {
                const sheet = get_sheet(btn);
                this.#render(sheet, btn);
            });
        });
    }
}

它有效,但是...

我在使用此类时注意到的是,当我在sheet.html中的<script>标签中编写javascript时;它不会在index.html中触发;这并不意味着允许任何脚本渗透到这些文件是安全的。我的猜测是,当获取重试读取文件时而不是“粘贴”到我们的index.html。

时,脚本会运行。

但是,如果您想导入一些JS怎么办?出色地;我注意到自定义元素可以正确渲染(如果它们在我们的app.js文件中定义);因此,您可以使用自动加载JS代码的自定义元件。

注意:我不能真正谈论这种方法的安全性;我会说还不错,但是,如果这些HTML文件被损坏,那么班级将无法了解,不要介意手工。

结论:使用框架ð

系列结论

在这4篇文章中,我准备从电子和桌面应用程序开始制定第一步。我必须说,与Web开发相比,与Web开发相比,我很惊讶的是,至少在此示例中。我认为,如果我在哪里深入研究这个世界,那将需要更多的设置。
我发现当然可以与电子合作而没有框架(在意识到自己可以使用一个应用之前,我已经完全构建了我的应用程序);但这会有所改善。
我喜欢它与我习惯的网络开发有多近,并且使用它感觉很不错,但是我无法真正将其与其他App-Dev框架相比。
但是,应该提到(The Electron Saga 0)在我旅途开始时的错误错误。他们确实引起了一些困惑和担忧。

总的来说,围绕这个新环境嘲笑,远离潜伏在我肩膀上的项目很有趣。
说到这,我应该回到那些。我希望您能从这个系列中得到一些东西。
再见! ð