摘要:上集回顧從零開始手把手教你實現(xiàn)一個一上一集我們介紹了什么是,為什么要用,以及我們要怎樣來實現(xiàn)一個。完成后,在命令行中輸入安裝下依賴。最后返回這個目標(biāo)節(jié)點。明天,我們迎接挑戰(zhàn),開始處理數(shù)據(jù)變動引起的重新渲染,我們要如何新舊,生成補(bǔ)丁,修改。
上集回顧
從零開始手把手教你實現(xiàn)一個Virtual DOM(一)
上一集我們介紹了什么是VDOM,為什么要用VDOM,以及我們要怎樣來實現(xiàn)一個VDOM。我們再來看一下這張藍(lán)圖,今天我們要實現(xiàn)的是這張圖的左半部分。
{ "name": "vdom", "version": "1.0.0", "description": "", "scripts": { "compile": "babel index.js --out-file compiled.js" }, "author": "", "license": "", "devDependencies": { "babel-cli": "^6.23.0", "babel-plugin-transform-react-jsx": "^6.23.0" } }
這里主要主要兩點:
devDependencies中依賴babel-cli和babel-plugin-transform-react-jsx這兩個庫,前者提供Babel的命令行功能,后者主要幫我們把jsx轉(zhuǎn)化成js。
scripts中我們指定了一條命令:complile,每次當(dāng)我們在當(dāng)前目錄下的命令行中敲npm run compile時,babal就會將我們的index.js轉(zhuǎn)化后新建一個compile.js文件。
完成后,在命令行中輸入npm install安裝下依賴。
.babelrc{ "plugins": [ ["transform-react-jsx", { "pragma": "h" // default pragma is React.createElement }] ] }
在babel的配置文件中,我們指定transform-react-jsx這個插件將轉(zhuǎn)化后的函數(shù)名設(shè)置為h。默認(rèn)的函數(shù)名是React.createElement,我們不依賴react,所以顯然換個自己的名字更合適。這里不清楚h是干什么的不要緊,等會看到代碼你就知道了。
index.htmlVDOM
這個HTML還是很直觀的,類似React,我們有一個根節(jié)點id是app。然后我們render函數(shù)最終生成的DOM會插入到app這個根節(jié)點里。注意我們引用的compile.js文件是babel根據(jù)等會要寫的index.js文件自動生成的。
index.js首先,我們用JSX來編寫“模板”:
function view() { return
接下來,我們要將JSX編譯成js, 也就是hyperscript。我們先用Babel編譯一下,看這段JSX轉(zhuǎn)成js會是什么樣子,打開命令行,輸入npm run compile,得到的compile.js:
function view() { return h( "ul", { id: "filmList", className: "list" }, h( "li", { className: "main" }, "Detective Chinatown Vol 2" ), h( "li", null, "Ferdinand" ), h( "li", null, "Paddington 2" ) ); }
可以看出h函數(shù)接收的參數(shù),第一個參數(shù)是node的類型,比如ul,li,第二個參數(shù)是node的屬性,之后的參數(shù)是node的children,假如child又是一個node的話,就會繼續(xù)調(diào)用h函數(shù)。
清楚了Babel會將我們的JSX編譯成什么樣子后,接下來我們就可以繼續(xù)在index.js中來寫h函數(shù)了。
function flatten(arr) { return [].concat(...arr) } function h(type, props, ...children) { return { type, props: props || {}, children: flatten(children) } }
我們的h函數(shù)主要的工作就是返回我們真正需要的hyperscript對象,只有三個參數(shù),第一個參數(shù)是節(jié)點類型,第二個參數(shù)是屬性對象,第三個是子節(jié)點的數(shù)組。
這里主要用了ES6的rest, spread參數(shù),不清楚代碼中兩個...分別是什么意思的可以先去看我的介紹ES6文章30分鐘掌握ES6/ES2015核心內(nèi)容(上)。簡單來說,rest就是上面的...children,它將函數(shù)多余的參數(shù)放到一個數(shù)組里,所以children此時變成了一個數(shù)組。而spread則是rest的逆運算,也就是上面的...arr,它將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列。
flatten(children)這個操作是因為children這個數(shù)組里的元素有可能也是個數(shù)組,那樣就成了一個二維數(shù)組,所以我們需要將數(shù)組拍平成一維數(shù)組。[].concat(...arr)是ES6寫法,傳統(tǒng)的寫法是[].concat.apply([], arr)
我們現(xiàn)在可以先來看一下h函數(shù)最終返回的對象長什么樣子。
function render() { console.log(view()) }
我們在render函數(shù)中打印出執(zhí)行完view()的結(jié)果,再npm run compile后,用瀏覽器打開我們的index.html,看控制臺輸出的結(jié)果。
可以,很完美!這個對象就是我們的VDOM了!
下面我們就可以根據(jù)VDOM, 來渲染真實DOM了。先改寫render函數(shù):
function render(el) { el.appendChild(createElement(view(0))) }
createElement函數(shù)生成DOM,然后再插入到我們在index.html中寫的根節(jié)點app。注意render函數(shù)式在index.html中被調(diào)用的。
function createElement(node) { if (typeof(node) === "string") { return document.createTextNode(node) } let { type, props, children } = node const el = document.createElement(type) setProps(el, props) children.map(createElement) .forEach(el.appendChild.bind(el)) return el } function setProp(target, name, value) { if (name === "className") { return target.setAttribute("class", value) } target.setAttribute(name, value) } function setProps(target, props) { Object.keys(props).forEach(key => { setProp(target, key, props[key]) }) }
我們來仔細(xì)看下createElement函數(shù)。假如說node,即VDOM的類型是文本,我們直接返回一個創(chuàng)建好的文本節(jié)點。否則的話,我們?nèi)〕鰊ode中類型,屬性和子節(jié)點, 先根據(jù)類型創(chuàng)建相應(yīng)的目標(biāo)節(jié)點,然后再調(diào)用setProps函數(shù)依次設(shè)置好目標(biāo)節(jié)點的屬性,最后遍歷子節(jié)點,遞歸調(diào)用createElement方法,將返回的子節(jié)點插入到剛剛創(chuàng)建的目標(biāo)節(jié)點里。最后返回這個目標(biāo)節(jié)點。
還需要注意的一點是,jsx中class的寫成了className,所以我需要特殊處理一下。
大功告成,complie后瀏覽器打開index.html看看結(jié)果吧。
今天我們成功的完成了藍(lán)圖的左半部分,將JSX轉(zhuǎn)化成hyperscript,再轉(zhuǎn)化成VDOM,最后根據(jù)VDOM生成DOM,渲染到頁面。明天,我們迎接挑戰(zhàn),開始處理數(shù)據(jù)變動引起的重新渲染,我們要如何DIFF新舊VDOM,生成補(bǔ)丁,修改DOM。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94603.html
摘要:可實際上并不是創(chuàng)造的,將這個概念拿過來以后融會貫通慢慢地成為目前前端最炙手可熱的框架之一。則是將再抽象一層生成的簡化版對象,這個對象也擁有上的一些屬性,比如等,但它是完全脫離于瀏覽器而存在的。所以今天我要手把手教大家怎么從零開始實現(xiàn)。 假如你的項目使用了React,你知道怎么做性能優(yōu)化嗎?你知道為什么React讓你寫shouldComponentUpdate或者React.PureCo...
摘要:函數(shù)依次做了這幾件事調(diào)用函數(shù),對比新舊兩個,根據(jù)兩者的不同得到需要修改的補(bǔ)丁將補(bǔ)丁到真實上當(dāng)計數(shù)器小于等于的時候,將加,再繼續(xù)下一次當(dāng)計數(shù)器大于的時候,結(jié)束下面我們來實現(xiàn)函數(shù)和函數(shù)。 上集回顧 【React進(jìn)階系列】從零開始手把手教你實現(xiàn)一個Virtual DOM(二) 上集我們實現(xiàn)了首次渲染從JSX=>Hyperscript=>VDOM=>DOM的過程,今天我們來看一下當(dāng)數(shù)據(jù)變動的時...
摘要:但如果你想更加高效地使用來開發(fā),成為大師,那下面我要傳授的這五招你一定得認(rèn)真學(xué)習(xí)一下了。雖然損失了一丟丟性能,但避免了無限的。所以我們需要設(shè)置,這些默認(rèn)行為將會被去掉以上兩點的優(yōu)化才能成功。陸續(xù)可能還會更新一些別的招數(shù),敬請期待。 本文面向?qū)ο笫怯幸欢╒ue.js編程經(jīng)驗的開發(fā)者。如果有人需要Vue.js入門系列的文章可以在評論區(qū)告訴我,有空就給你們寫。 對大部分人來說,掌握Vue.j...
摘要:模塊化是隨著前端技術(shù)的發(fā)展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調(diào)也不等同于異步。將會討論安全的類型檢測惰性載入函數(shù)凍結(jié)對象定時器等話題。 Vue.js 前后端同構(gòu)方案之準(zhǔn)備篇——代碼優(yōu)化 目前 Vue.js 的火爆不亞于當(dāng)初的 React,本人對寫代碼有潔癖,代碼也是藝術(shù)。此篇是準(zhǔn)備篇,工欲善其事,必先利其器。我們先在代...
摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運,我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...
閱讀 2164·2021-11-11 16:55
閱讀 1685·2019-08-30 15:54
閱讀 2817·2019-08-30 15:53
閱讀 2211·2019-08-30 15:44
閱讀 1152·2019-08-30 15:43
閱讀 965·2019-08-30 11:22
閱讀 1942·2019-08-29 17:20
閱讀 1566·2019-08-29 16:56