создание vanilla js web-компонента с отдельными html и js файлами - PullRequest
0 голосов
/ 08 апреля 2019

При создании ванильных веб-компонентов JS я пытаюсь найти способ сохранить шаблон HTML вне файла JS, предпочтительно в отдельном HTML-файле.

Я изучил несколько реализаций нативногоРеализации веб-компонентов JS, в частности, здесь , отдельный файл и очень хорошая запись здесь .

Все реализации заканчивают тем, что помещают htmlШаблон внутри JS, используя строковые литералы или аналогичные методы.У меня вопрос, возможно ли вообще сделать два отдельных файла, например my-component.html для шаблона и my-component.js для кода JS?

Я видел, как этот подход хорошо работает в среде Aurelia, он очень чистыйи хранит код там, где он принадлежит.

Я попытался использовать импорт html, создав html-файл для шаблона и включив в него js.

<link rel="import" href="my-component.html">

, который теоретически должен работать, но импорт html уже отменен браузерами.

Мой второй подход, который мне кажется немного хакерским, но он работает, это получить шаблон HTML с сервера в connectedCallback

// my-component.js

class MyComponent extends HTMLElement {

    constructor() {
        super();
    }

    connectedCallback() {
        this.initShadowDom();

    }

    async initShadowDom() {
        let shadowRoot = this.attachShadow({mode: 'open'});
        shadowRoot.innerHTML = await this.template;
    }

    async fetchData() {
        return await fetch('my-template-url')
            .then(function(response) {
                return response.text();
            });
    }

    get template() {

        return (async () => {
            return await this.fetchData();
        })();
    }
}
customElements.define('my-component', MyComponent);

со стороны сервера. Я просто возвращаю чистый HTML

// my-component.html

<style>
@import 'https://fonts.googleapis.com/icon?family=Material+Icons';
@import 'https://code.getmdl.io/1.3.0/material.${this.theme}.min.css';
@import 'http://fonts.googleapis.com/css?family=Roboto:300,400,500,700';
@import 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css'
}
table {
    border-collapse: collapse;
}
td {
    text-align: center;
    border: 1px solid #f7f7f7;
    padding: 1rem;
}
th {
    background-color: #f7f7f7;
    text-align: center;
    padding: 1em;
    border: 1px solid #e9e9e9;
}
    </style>
<div class="search-list table-responsive">
<table width="100%" class="table table-bordered table-striped table-hover">
    <thead class="thead-light">
    <tr>
        <th width="1rem">
            <input type="checkbox">
        </th>
        <th>
            ID
        </th>
        <th>
            name
        </th>

    </tr>
    </thead>
    <tbody>
    <tr>
        <td><input type="checkbox"></td>
        <td>
            1
        </td>
        <td>
            some name
        </td>

    </tr>

    </tbody>
    </table>
</div>

Обратите внимание, как я вообще пропустил тег <template> в ответе от сервера, так как, очевидно, если я использую тег <template>, мне придется использовать синтаксический анализ dom, чтобы фактически поместить html вdom.

Это работает, но выглядит так глупо.

У кого-нибудь есть лучший подход?

1 Ответ

0 голосов
/ 08 апреля 2019

У вас хорошее решение, но вы можете добавить код Javascript:

class MyComponent extends HTMLElement {

    async connectedCallback() {
        let res = await fetch( 'my-component.html' )

        this.attachShadow( { mode: 'open' } )
            .innerHTML = await res.text()
    }

}
customElements.define( 'my-component', MyComponent )
...