Как упаковать или импортировать HTML-шаблоны без HTML-импорта
Так как Html-импорт теперь не поддерживается в Chrome ( https://www.chromestatus.com/feature/5144752345317376) и будет удален, мне интересно, какие есть альтернативы.
В настоящее время я использую Html-Imports для импорта Html-шаблонов. Пока я вижу только две альтернативы:
- Объединение всех HTML-файлов в один файл. Это также улучшит время загрузки, но уменьшит инкапсуляцию и модульность. Существует полимерный пакет, который будет выполнять эту работу путем обхода HTML-Import-Statements в отдельных HTML-файлах. Но это будет означать, что HTML-импорт остается в моем коде, даже если в будущем он не будет поддерживаться никакими браузерами.
- Сборка какого-то загрузчика модулей с использованием XHttpRequests и объединение шаблонов в один HTML-файл во время выполнения. Это сохранит инкапсуляцию и модульность, но у меня будет неприятный запах, так как я в основном перестрою import-заявления самостоятельно.
Есть ли новый ванильный способ импорта HTML-шаблонов? (Под "ванилью" я подразумеваю путь без каких-либо дополнительных инструментов, таких как прекомпилятор или пакет)
2 ответа
Устаревание HTML Imports существенно изменило порядок загрузки ресурсов. Пользовательские элементы, по сути, стали в первую очередь сценариями, а не шаблонами. Если вашему элементу нужен шаблон, загрузите его из скрипта. Если нет, просто иди на работу. Честно говоря, в то время как я был устойчив к этому в течение первых нескольких недель, я полюбил это. И оказывается, что загрузка внешних ресурсов, таких как шаблоны, не так уж и плоха.
Вот простой код, который будет загружать шаблон HTML из внешнего файла:
используя async/await:
async function getTemplate(filepath) {
let response = await fetch(filepath);
let txt = response.text();
let html = new DOMParser().parseFromString(txt, 'text/html');
return html.querySelector('head > template');
}
Обещают на основе:
function getTemplate(filepath) {
return fetch(filepath)
.then(response => {
let txt = response.text();
let html = new DOMParser().parseFromString(txt, 'text/html');
return html.querySelector('template');
});
}
Оба могут быть вызваны с обоими из следующих:
асинхронная / ждут:
let tpl = await getTemplate('path/to/template.html');
Обещания:
getTemplate('path/to/template.html')
.then(function doSomething(tpl) {
// Put your code here...
});
Полученный код достаточно прост, чтобы его можно было реализовать без особых усилий различными способами. На самом деле, у меня есть небольшой суперкласс, который обрабатывает его для меня, и все мои пользовательские элементы наследуются от него. Вместо этого вы можете использовать миксин, что я и делал в прошлом.
Тяжелая работа - это просто изменение порядка, и даже это не очень сложно, если вы не используете тысячи компонентов. Вероятно, это может быть автоматизировано с очень небольшим количеством работы.
index.html:
<script type="module">
import { CustomHTMLElement } from './CustomHTMLElement.js'
customElements.define('custom-html-element', CustomHTMLElement)
</script>
<custom-html-element></custom-html-element>
CustomHTMLElement.js:
import { createTemplate } from './createTemplate.js'
const template = createTemplate(`
<template>
<style>
.box {
width: 2rem;
height: 2rem;
background-color: red;
}
</style>
<div class="box"></div>
</template>
`)
export class CustomHTMLElement extends HTMLElement {
constructor() {
super()
const templateContent = template.content
const shadowRoot = this.attachShadow({mode: 'closed'})
shadowRoot.appendChild(templateContent.cloneNode(true))
}
}
createTemplate.js:
import { createDOM } from './createDOM.js'
export function createTemplate(templateText) {
const dom = createDOM(templateText)
const template = dom.querySelector('template')
return template
}
createDOM.js:
export function createDOM(htmlText) {
return new DOMParser().parseFromString(htmlText, 'text/html')
}
См. Https://github.com/SanjoSolutions/web-components для кода, лицензированного по безлицензионной лицензии.