htm 是 preact 做者的新尝试,利用原生 HTML 规范支持了类 JSX 的写法。javascript
htm 没有特别的文档,假如你用过 JSX,那只须要记住下面三个不一样点:html
className
-> class
。<div class=foo>
。<div><!-- don't delete this! --></div>
。另外支持了可选结束标签、快捷组件 End 标签,不过这些本身发明的语法不建议记忆。
用法也没什么特别的地方,你能够利用 HTML 原生规范,用直觉去写 JSX:前端
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> `;
很显然,因为跳过了 JSX 编译,换成了原生的 Template Strings ,因此全部组件、属性部分都须要改为 ${}
语法,好比:java
<${Header}>
这种写法略显别扭,但总体上仍是蛮直观的。react
你不必定非要用在项目环境中,但当你看到这种语法时,心里必定不由自主的 WoW,居然还有这种写法!webpack
下面将带你一块儿分析 htm 的源码,看看做者是如何作到的。git
你能够先本身尝试阅读,源码加上注释一共 90 行:源码。github
好了,欢迎继续阅读。web
首先你要认识到, htm
+ vhtml
才等于你上面看到的 DEMO。typescript
Htm
是一个 dom template 解析器,它能够将任何 dom template 解析成一颗语法树,而这个语法树的结构是:
interface VDom { tag: string; props: { [attrKey: string]: string; }; chindren: VDom[]; }
咱们看一个 demo:
function h(tag, props, ...children) { return { tag, props, children }; } const html = htm.bind(h); html` <div>123</div> `; // { tag: "div", props: {}, children: ["123"] }
那具体是怎么作语法解析的呢?
其实实现方式有点像脑经急转弯,毕竟解析 dom template 是浏览器引擎作的事,规范也早已定了下来,有了规范和实现,固然不必重复造轮子,办法就是利用 HTML 的 AST 生成咱们须要的 AST。
首先建立一个 template
元素:
const TEMPLATE = document.createElement("template");
再装输入的 dom template 字符串塞入(做者经过正则,机智的将本身支持的额外语法先转化为标准语法,再交给 HTML 引擎):
TEMPLATE.innerHTML = str;
最后咱们会发现进入了 walk
函数,经过 localName
拿到标签名;attributes
拿到属性值,经过 firstChild
与 nextSibling
遍历子元素继续走 walk
,最后 tag
props
children
三剑客就生成了。
可能你还没看完,就已经结束了。笔者分析这个库,除了告诉你做者的机智思路,还想告诉你的是,站在巨人的肩膀造轮子,真的事半功倍。
VDom 是个抽象概念,它负责将实体语法树解析为 DOM。这个工具能够是 preact、vhtml,或者由你本身来实现。
固然,你也能够利用这个 AST 生成 JSON,好比:
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' // } // }
读到这,你以为还有哪些 “VDom” 能够写呢?其实任何能够根据 tag
props
children
推导出的结构均可以写成解析插件。
htm 是一个教科书般借力造论子案例:
innerHTML
会自动生成的标准 AST,解析出符合本身规范的 AST,这实际上是进一步抽象 AST。不过这也带来了一个问题:依赖原生 DOM API 会致使没法运行在 NodeJS 环境。
想想你如今开发的工具库,有没有能够借力的地方呢?有哪些点能够经过借力作得更好从而实现共赢呢?欢迎留下你的思考。
讨论地址是: 精读《Htm - Hyperscript 源码》 · Issue #114 · dt-fe/weekly
若是你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。