HTM — альтернатива JSX? Или другой вариант?
Preact | Omi |
---|---|
htm
Полное название — Hyperscript Tagged Markup, синтаксис которого похож на JSX.По сравнению с JSX его самые большие преимущества:
- Компилятор не требуется
- Работает непосредственно в современных браузерах, если ваш браузер поддерживает это.Tagged templatesпросто хорошо
Таким образом, вы можете использовать его непосредственно в React, Preact или omi и запускать прямо в браузере без какой-либо компиляции. он используетTagged templatesи анализатор HTML, который поставляется с браузером.
очень маленький размер
- Используйте только 700 байт непосредственно в браузере, менее 1 КБ
- Используйте только 500 байт в preact
- При использованииbabel-plugin-htmТребуется только 0 байт
Синтаксис - как у JSX, так и у lit-html
htm вдохновлен lit-html, но включает следующие функции из JSX:
- Остальные расширения:
<div ...${props}>
- Этикетка самозакрывающаяся:
<div />
- Имя динамического тега:
<${tagName}>
(tagName
ссылка на элемент) - Логическое свойство:
<div draggable />
Улучшения JSX
htm
Действительно, на основе JSX было сделано множество улучшений, таких как следующие функции, которых нет в JSX:
- Компилятор не нужен, запускается прямо в браузере
- Необязательный способ точки с запятой в HTML:
<div class=foo>
- Самозакрытие HTML:
<img src=${url}>
- Необязательный закрывающий тег:
<section><h1>this is the whole template!
- Закрывающий тег компонента:
<${Footer}>footer content<//>
- HTML-комментарии поддерживаются:
<div><!-- don't delete this! --></div>
- Установитьlit-html VSCode extensionподсветка синтаксиса
статус проекта
Первоначальная цель HTM состояла в том, чтобы создать обертку вокруг преиздота, используйте его некомбированным в вашем браузере. Я хочу использовать виртуальный DOM, но я не хочу строить инструменты напрямую модуль ES.
Это означает отказ от JSX, ближайшей альтернативой является [Tagged_templates]. Итак, я написал эту библиотеку, чтобы исправить разницу между ними. Оказывается, этот метод не зависит от фреймворка, поэтому он должен работать с большинством библиотек виртуальных DOM.
Установить
htm
Опубликовано в npm, вы также можете посетитьunpkg.comCDN:
npm i htm
Получить его из unpkg:
import htm from 'https://unpkg.com/htm?module'
const html = htm.bind(React.createElement);
// just want htm + preact in a single file? there's a highly-optimized version of that:
import { html, render } from 'https://unpkg.com/htm/preact/standalone.mjs'
руководство пользователя
теперь, когдаhtm
является универсальной библиотекой, и нам нужно сообщить ей, как «компилировать» наши шаблоны.
Цель должна быть формойh(tag, props, ...children)
(hyperscript), и может вернуть что угодно.
// 这是我们的 h 函数。现在,它只返回一个描述对象。
function h(tag, props, ...children) {
return { tag, props, children };
}
чтобы использовать этоh
нам нужно передать привязкуhtm
нашимh
для создания собственной функции HTML-тега:
import htm from 'htm';
const html = htm.bind(h);
Теперь у нас естьhtml
Теги шаблона, которые можно использовать для создания объектов в формате, созданном выше, например:
import htm from 'htm';
function h(tag, props, ...children) {
return { tag, props, children };
}
const html = htm.bind(h);
console.log( html`<h1 id=hello>Hello world!</h1>` );
// {
// tag: 'h1',
// props: { id: 'hello' },
// children: ['Hello world!']
// }
Например
Интересно посмотреть, как все это выглядит? Это рабочее приложение!
Это один файл HTML без сборок или инструментов. Вы можете редактировать его с помощью Nano.
<!DOCTYPE html>
<html lang="en">
<title>htm Demo</title>
<script type="module">
import { html, Component, render } from 'https://unpkg.com/htm/preact/standalone.mjs';
class App extends Component {
addTodo() {
const { todos = [] } = this.state;
this.setState({ todos: todos.concat(`Item ${todos.length}`) });
}
render({ page }, { todos = [] }) {
return html`
<div class="app">
<${Header} name="ToDo's (${page})" />
<ul>
${todos.map(todo => html`
<li>${todo}</li>
`)}
</ul>
<button onClick=${() => this.addTodo()}>Add Todo</button>
<${Footer}>footer content here<//>
</div>
`;
}
}
const Header = ({ name }) => html`<h1>${name} List</h1>`
const Footer = props => html`<footer ...${props} />`
render(html`<${App} page="All" />`, document.body);
</script>
</html>
ЭтоПредварительная онлайн-версия.
Замечательно? Обратите внимание, что есть только один импорт — здесь мы просто используемimport
Интегрируйте с Preact, так как его легче импортировать и он меньше по размеру.
Тот же пример отлично работает без готовой версии, просто используя два импорта:
import { h, Component, render } from 'preact';
import htm from 'htm';
const html = htm.bind(h);
render(html`<${App} page="All" />`, document.body);
другое использование
потому чтоhtm
предназначен для удовлетворения тех же потребностей, что и JSX, поэтому вы можете использовать его везде, где вы используете JSX.
** использоватьvhtmlСоздать HTML:**
import htm from 'htm';
import vhtml from 'vhtml';
const html = htm.bind(vhtml);
console.log( html`<h1 id=hello>Hello world!</h1>` );
// '<h1 id="hello">Hello world!</h1>'
Webpack configuration via jsxobj: (details here)
import htm from 'htm';
import jsxobj from 'jsxobj';
const html = htm.bind(jsxobj);
console.log(html`
<webpack watch mode=production>
<entry path="src/index.js" />
</webpack>
`);
// {
// watch: true,
// mode: 'production',
// entry: {
// path: 'src/index.js'
// }
// }
omi-html
использовать в омиhtm
Usage of omi-html
import { define, render, WeElement } from 'omi'
import 'omi-html'
define('my-counter', class extends WeElement {
static observe = true
data = {
count: 1
}
sub = () => {
this.data.count--
}
add = () => {
this.data.count++
}
render() {
return html`
<div>
<button onClick=${this.sub}>-</button>
<span>${this.data.count}</span>
<button onClick=${this.add}>+</button>
</div>`
}
})
render(html`<my-counter />`, 'body')
запускать прямо в браузере
<script src="https://unpkg.com/omi"></script>
<script src="https://unpkg.com/omi-html"></script>
<script>
const { define, WeElement, render } = Omi
define('my-counter', class extends WeElement {
install() {
this.constructor.observe = true
this.data.count = 1
this.sub = this.sub.bind(this)
this.add = this.add.bind(this)
}
sub() {
this.data.count--
}
add() {
this.data.count++
}
render() {
return html`
<div>
<button onClick=${this.sub}>-</button>
<span>${this.data.count}</span>
<button onClick=${this.add}>+</button>
</div>
`}
})
render(html`<my-counter />`, 'body')
</script>