1 引言
htm 是 preact 作者的新尝试,利用原生 HTML 规范支持了类 JSX 的写法。
2 概要
htm 没有特别的文档,假如你用过 JSX,那只需要记住下面三个不同点:
className
->class
。- 标签引号可选(回归 html 规范):
<div class=foo>
。 - 支持 HTML 模式的注释:
<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 ,所以所有组件、属性部分都需要改成 ${}
语法,比如:
<${Header}>
这种写法略显别扭,但整体上还是蛮直观的。
你不一定非要用在项目环境中,但当你看到这种语法时,内心一定情不自禁的 WoW,竟然还有这种写法!
下面将带你一起分析 htm 的源码,看看作者是如何做到的。
3 精读
你可以先自己尝试阅读,源码加上注释一共 90 行:源码。
好了,欢迎继续阅读。
首先你要认识到, htm
+ vhtml
才等于你上面看到的 DEMO。
Htm
Htm
是一个 dom template 解析器,它可以将任何 dom template 解析成一颗语法树,而这个语法树的结构是:
interface VDom {
tag: string;
props: {
[attrKey: string]: string;
};
children: 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
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
推导出的结构都可以写成解析插件。
4 总结
htm 是一个教科书般借力造论子案例:
- 利用
innerHTML
会自动生成的标准 AST,解析出符合自己规范的 AST,这其实是进一步抽象 AST。 - 利用原有库进行 DOM 解析,比如 preact 或 vhtml。
- 基于第二点,所以可以生成任何目标代码,比如 json,pdf,excel 等等。
不过这也带来了一个问题:依赖原生 DOM API 会导致无法运行在 NodeJS 环境。
想一想你现在开发的工具库,有没有可以借力的地方呢?有哪些点可以通过借力做得更好从而实现双赢呢?欢迎留下你的思考。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=17894,转载请注明出处。
评论0