摘要:我們用原生的對(duì)象來(lái)描述我們要渲染的東西,并稱這類對(duì)象為。下一步是將元素及其子元素渲染成。所以,將會(huì)使用來(lái)表示文本節(jié)點(diǎn),并使用來(lái)裝文本值。創(chuàng)建添加事件監(jiān)聽(tīng)設(shè)置屬性遞歸渲染子元素將添加到父內(nèi)我們目前創(chuàng)建了一個(gè)可以渲染元素及其子元素為的方法。
翻譯自這里:https://engineering.hexacta.c...
本系列的目的是創(chuàng)建類似于React的一個(gè)簡(jiǎn)易的工具庫(kù)。
開(kāi)始之前,我們先看下我們要用到的DOM API:
// 通過(guò)id查找元素 const domRoot = document.getElementById("root"); // 根據(jù)執(zhí)行標(biāo)簽名創(chuàng)建元素 const domInput = document.createElement("input"); // 設(shè)置元素屬性 domInput["type"] = "text"; domInput["value"] = "Hi world"; domInput["className"] = "my-class"; // 添加事件監(jiān)聽(tīng) domInput.addEventListener("change", e => alert(e.target.value)); // 創(chuàng)建文本節(jié)點(diǎn) const domText = document.createTextNode(""); // 設(shè)置節(jié)點(diǎn)內(nèi)容 domText["nodeValue"] = "Foo"; // 往頁(yè)面上添加元素 domRoot.appendChild(domInput); // 往頁(yè)面上添加文本節(jié)點(diǎn) domRoot.appendChild(domText);
注意到這里我們給元素設(shè)置了properties而不是attributes,而且只有有效的properties才能被設(shè)置。
Didact Elements我們用原生的JS對(duì)象來(lái)描述我們要渲染的東西,并稱這類對(duì)象為Didact Elements。這些元素對(duì)應(yīng)的JS對(duì)象都有兩個(gè)必要的屬性:type和props。type可以是個(gè)字符串也可以是一個(gè)函數(shù),但在我們介紹組件之前我們先只使用字符串。props是一個(gè)可以為空(null)的對(duì)象。props下還可以含有children屬性,children屬性值為一個(gè)裝有Didact Elements的數(shù)組。
我們后面將會(huì)頻繁的使用Didact Elements,所以我們會(huì)用元素稱呼Didact Elements。不要和HTML的元素搞混了,HTML元素會(huì)被稱作DOM元素或者使用命名變量時(shí)干脆就叫dom。
舉個(gè)例子,我們會(huì)用下面這個(gè)對(duì)象:
const element = { type: "div", props: { id: "container", children: [ { type: "input", props: { value: "foo", type: "text" } }, { type: "a", props: { href: "/bar" } }, { type: "span", props: {} } ] } };
來(lái)描述下面這個(gè)dom:
Didact Elements和React Elements很像。但通常情況下你不會(huì)使用JS手動(dòng)去創(chuàng)建一個(gè)React Elements,更多的是使用JSX或者是createElement方法來(lái)創(chuàng)建。在Didact中我們也會(huì)使用相同的方法創(chuàng)建元素,但會(huì)將這部分內(nèi)容放在下一節(jié)。
Render DOM Elements下一步是將元素及其子元素渲染成dom。我們使用render(類似于ReactDOM.render)方法來(lái)接收一個(gè)元素和一個(gè)dom容器。這個(gè)方法會(huì)將這個(gè)元素描述的dom結(jié)構(gòu)創(chuàng)建出來(lái),并添加到容器內(nèi)。
function render(element, parentDom){ const { type, props } = element; const dom = document.createElement(type); const childElements = props.children || []; childElements.forEach(childElement => render(childElement, dom)); parentDom.appendChild(dom); }
我們現(xiàn)在仍沒(méi)有處理屬性和事件。我們先用Object.keys來(lái)獲取props中的屬性名字,然后循環(huán)將它們?cè)O(shè)定到元素上:
function render(element, parentDom){ const { type, props } = element; const dom = document.createElement(type); const isListener = name => name.startsWith("on"); Object.keys(props).filter(isListener).forEach(name => { const eventType = name.toLowerCase().substring(2); dom.addEventListener(eventType, props[name]); }) const isAttribute = name => !isListener(name) && name != "children"; Object.keys(props).filter(isAttribute).forEach(name => { dom[name] = props[name]; }) const childElements = props.children || []; childElements.forEach(childElement => render(childElement, dom)); parentDom.appendChild(dom); }Render DOM Text Nodes
目前render還不支持文本節(jié)點(diǎn)。首先我們要定義文本節(jié)點(diǎn)是什么樣的。在react中,一個(gè)Foo這樣的元素需要這樣描述:
const reactElement = { type: "span", props: { children: ["Foo"] } }
注意到這里的子元素已經(jīng)不是對(duì)象,而只是一個(gè)字符串。這和我們對(duì)Didact Elements的定義有不一樣:children應(yīng)該是裝有Didact Elements的數(shù)組,并且所有元素都有type和props屬性。如果我們繼續(xù)遵守這個(gè)規(guī)則接下來(lái)我們將較少使用if的次數(shù)。所以,Didact Elements將會(huì)使用type="TEXT_ELEMENT"來(lái)表示文本節(jié)點(diǎn),并使用nodeValue來(lái)裝文本值。例如下面這樣:
const textElement = { type: "span", props: { children: [ { type: "TEXT_ELEMENT", props: { nodeValue: "Foo" } } ] } };
現(xiàn)在我們已經(jīng)定義好了能夠渲染的文本節(jié)點(diǎn)。和其他節(jié)點(diǎn)不同的是,文本節(jié)點(diǎn)需要使用createTextNode來(lái)創(chuàng)建而不是createElement,而nodeValue會(huì)通過(guò)相同方法來(lái)設(shè)置。
function render(element, parentDom) { const { type, props } = element; // 創(chuàng)建DOM const isTextElement = type === "TEXT_ELEMENT"; const dom = isTextElement ? document.createTextNode("") : document.createElement(type); // 添加事件監(jiān)聽(tīng) const isListener = name => name.startsWith("on"); Object.keys(props).filter(isListener).forEach(name => { const eventType = name.toLowerCase().substring(2); dom.addEventListener(eventType, props[name]); }); // 設(shè)置屬性 const isAttribute = name => !isListener(name) && name != "children"; Object.keys(props).filter(isAttribute).forEach(name => { dom[name] = props[name]; }); // 遞歸渲染子元素 const childElements = props.children || []; childElements.forEach(childElement => render(childElement, dom)); // 將dom添加到父dom內(nèi) parentDom.appendChild(dom); }Summary
我們目前創(chuàng)建了一個(gè)可以渲染元素及其子元素為DOM的render方法。下一步我們需要一個(gè)快速簡(jiǎn)單的方法來(lái)創(chuàng)建元素。下一節(jié)我們將在Didact中使用JSX。
下一節(jié):
https://engineering.hexacta.c...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/99669.html
摘要:渲染元素開(kāi)場(chǎng)白接著上一節(jié)的講解后我們大概清楚了以下幾個(gè)事兒知道是個(gè)什么東東為什么要推薦使用以及的一些基本語(yǔ)法。本篇文章談一下是怎么渲染元素的。更新已渲染的元素元素是不可變的,一旦你創(chuàng)建了一個(gè)元素,就不能再修改其子元素或任何屬性。 React-渲染元素 開(kāi)場(chǎng)白 接著上一節(jié)JSX的講解后:我們大概清楚了以下幾個(gè)事兒: 知道JSX是個(gè)什么東東 為什么React要推薦使用JSX 以及JSX...
摘要:傳統(tǒng)算法通過(guò)循環(huán)遞歸對(duì)節(jié)點(diǎn)進(jìn)行依次對(duì)比,效率低下,算法復(fù)雜度達(dá)到,其中是樹(shù)中節(jié)點(diǎn)的總數(shù)。對(duì)于同一層級(jí)的一組子節(jié)點(diǎn),它們可以通過(guò)唯一進(jìn)行區(qū)分。當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除掉,不會(huì)用于進(jìn)一步的比較。 https://zhuanlan.zhihu.com/p/... React diff 會(huì)幫助我們計(jì)算出 Virtual DOM 中真正變化的部分,并只針對(duì)該部分進(jìn)行實(shí)...
摘要:事件行為在瀏覽器中保持一次,并且符合標(biāo)準(zhǔn)。主要是進(jìn)行修復(fù)。事件已經(jīng)在移動(dòng)上支持。阻止已經(jīng)在上存在的事件錯(cuò)誤處理。然后對(duì)應(yīng)的將會(huì)被打包送往客戶端。在中棄用,現(xiàn)在正式刪除。是運(yùn)行于一個(gè)嚴(yán)格的安全策略下成為可能。增加警告提示非生產(chǎn)環(huán)境。 ??寫(xiě)在開(kāi)頭 閱讀React官網(wǎng)的 RECENT POSTS的個(gè)人翻譯/摘要(部分)。 英文片段為官網(wǎng)原文片段。 原文地址 ??為什么要使用React ...
摘要:注不做翻譯是中最小的構(gòu)建部件。在里渲染讓我們看一下在下面有在你文件中無(wú)處不在的標(biāo)簽我們會(huì)把這元素成為元素因?yàn)榈乃袞|西都會(huì)放在這個(gè)元素里面。通過(guò)方法,我們能吧渲染到我們根節(jié)點(diǎn)上。更新被渲染的是不可變的。 下面是react官方文檔的個(gè)人翻譯,如有翻譯錯(cuò)誤,請(qǐng)多多指出原文地址:https://facebook.github.io/re...特別感謝Hevaen,同時(shí)也向豪大React群所有...
閱讀 3101·2021-11-15 11:39
閱讀 1669·2021-08-19 10:56
閱讀 1218·2019-08-30 14:12
閱讀 3873·2019-08-29 17:29
閱讀 846·2019-08-29 16:21
閱讀 3540·2019-08-26 12:22
閱讀 1633·2019-08-23 16:30
閱讀 1178·2019-08-23 15:25