htm 是 preact 做者的新嘗試,利用原生 HTML 規範支持了類 JSX 的寫法。javascript
htm 沒有特別的文檔,假如你用過 JSX,那隻須要記住下面三個不一樣點:html
className
-> class
。<div class=foo>
。<div><!-- don't delete this! --></div>
。另外支持了可選結束標籤、快捷組件 End 標籤,不過這些本身發明的語法不建議記憶。前端
用法也沒什麼特別的地方,你能夠利用 HTML 原生規範,用直覺去寫 JSX:java
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 ,因此全部組件、屬性部分都須要改爲 ${}
語法,好比:react
<${Header}>
這種寫法略顯彆扭,但總體上仍是蠻直觀的。webpack
你不必定非要用在項目環境中,但當你看到這種語法時,心裏必定不由自主的 WoW,居然還有這種寫法!git
下面將帶你一塊兒分析 htm 的源碼,看看做者是如何作到的。github
你能夠先本身嘗試閱讀,源碼加上註釋一共 90 行:源碼。web
好了,歡迎繼續閱讀。typescript
首先你要認識到, htm
+ vhtml
纔等於你上面看到的 DEMO。
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 環境。
想想你如今開發的工具庫,有沒有能夠借力的地方呢?有哪些點能夠經過借力作得更好從而實現共贏呢?歡迎留下你的思考。
若是你想參與討論,請點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。