HTM - JSX 的替代品?仍是另外一种选择?

HTM - JSX 的替代品?仍是另外一种选择?

Preact Omi
hyperscript tagged markup demo hyperscript tagged markup demo

原文连接javascript

htm 全称是 Hyperscript Tagged Markup,是一款与 JSX 语法相似的东西,相比 JSX 它最大的优势是:html

  • 不须要编译器
  • 直接在现代浏览器中运行,只要你的浏览器支持 Tagged templates 就行

因此,你能够直接在 react、preact 或者 omi 中使用而且直接在浏览器中运行,不须要任何编译。它利用了 Tagged templates 和浏览器自带的 HTML parser。java

极小的尺寸

  • 直接在浏览器中使用只有 700 字节,1KB 都不到
  • 在 preact 中使用只有 500 字节
  • 若是使用 babel-plugin-htm 只须要 0 字节

语法 - 像 JSX 也像 lit-html

htm 是受 lit-html 启发,可是包含了 JSX 里的这些特性:react

  • 剩余扩展: <div ...${props}>
  • 标签自关闭: <div />
  • 动态标签名: <${tagName}> ( tagName 是元素的引用)
  • 布尔属性: <div draggable />

对 JSX 的改进

htm 确确实实地基于 JSX 之上作了大量改进,好比下面这些特性是 JSX 所没有的:webpack

  • 不须要编译器,直接在浏览器中运行
  • 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最初的目标是在Preact周围建立一个包装器,使用它在浏览器中不受干扰。我想使用虚拟DOM,但我不想用构建工具,直接使用ES模块。git

这意味着要放弃JSX,最接近的替代方案是 [Tagged_templates]。因此,我写了这个库来修补二者之间的差别。事实证实,该技术是框架无关的,所以它应该与大多数虚拟 DOM 库一块儿工做。github

安装

htm 发布到了 npm, 也能够访问 unpkg.com 的 CDN:web

npm i htm
复制代码

从unpkg获取:npm

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>
复制代码

这是一个Preact 线上版本.

那真是太好了?注意,只有一个导入-这里咱们只使用了 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

在 omi 中使用 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>
复制代码

Star & Fork

相关文章
相关标签/搜索