摘要:前言的火熱程度已經(jīng)達(dá)到了個(gè),本系列文章主要用簡單的代碼來實(shí)現(xiàn)一個(gè),來了解虛擬算法以及和的設(shè)計(jì)。要想將虛擬轉(zhuǎn)成真實(shí)并渲染到頁面上,就需要調(diào)用,比如這段代碼轉(zhuǎn)換后的樣子這時(shí),會(huì)將掛載到為的下,從而在頁面上顯示出來。
前言
react的火熱程度已經(jīng)達(dá)到了94.5k個(gè)start,本系列文章主要用簡單的代碼來實(shí)現(xiàn)一個(gè)react,來了解JSX、虛擬DOM、diff算法以及state和setState的設(shè)計(jì)。
提到react,當(dāng)然少不了vue,vue的api設(shè)計(jì)十分簡單 上手也非常容易,但黑魔法很多,使用起來有點(diǎn)虛, 而react沒有過多的api,它的深度體現(xiàn)在設(shè)計(jì)思想上,使用react開發(fā)則讓人比較踏實(shí)、能拿捏的住,這也是我喜歡react的原因之一。
JSX寫react怎么少的了JSX,JSX是什么,讓我來看個(gè)例子
現(xiàn)在有下面這段代碼:
const el =Hello Javascript
這樣的js代碼如果不經(jīng)過處理會(huì)報(bào)錯(cuò),jsx是語法糖,它讓這段代碼合法化,通過babel轉(zhuǎn)化后是這樣的:
const el = React.createElement( "h3", { className: "title" }, "Hello Javascript" )
這種例子官網(wǎng)首頁也有demo
準(zhǔn)備開始開始編碼之前,先介紹兩個(gè)東西:parcel和babel-plugin-transform-jsx,等會(huì)我們用parcel搭建一個(gè)開發(fā)工程,babel-plugin-transform-jsx是babel的一個(gè)插件,它可以將jsx語法轉(zhuǎn)成React.createElement(...)。
下面我們開始
簡單的搭建parcel這里就不介紹了,一句話概況就是為你生成一個(gè)零配置的開發(fā)環(huán)境。
yarn global add parcel-bundler 或 npm install -g parcel-bundler
新建項(xiàng)目文件夾,這里取名為simple-react
在simple-react中執(zhí)行 yarn init -y 或 npm init -y 生成package.json
創(chuàng)建一個(gè)index.html
創(chuàng)建src文件夾 再在src下創(chuàng)建index.js 然后再index.html中引入index.js
如果你先麻煩,可以直接下載源碼修改。
以上步驟完可能不完整,最好參考parcel里的內(nèi)容。以上工作完成后,我們需要安裝babel-plugin-transform-jsx:
npm insatll babel-plugin-transform-jsx --save-dev 或者 yarn add babel-plugin-transform-jsx --dev
然后添加.babelrc文件,并在該文件中加入下面這段代碼:
{ "presets": ["env"], "plugins": [["transform-jsx", { "function": "React.createElement" }]] }
上面代碼的意思是 使用transform-jsx插件,并配置為通過React.createElement方法來解析JSX,當(dāng)然你也可以不用React.createElement和自定義方法,比如preact使用的h方法。
React.createElement()現(xiàn)在我們?cè)?b>index.js里開始編碼。
首先寫入代碼:
const el =Hello Javascript
; console.log(el);
我們?cè)谑裁炊疾粚懙那闆r下,打印看看el是什么。
打印報(bào)錯(cuò):React沒有定義。 這是因?yàn)樵?b>.babelrc文件中,我們使用的這段代碼起了作用:
["transform-jsx", { "function": "React.createElement" }]
上面說過,它會(huì)通過React.createElement方法來轉(zhuǎn)譯JSX,那么我們就給出這個(gè)方法:
我們把剛才那段代碼改變一下:
const React = { createElement: function(...args) { return args[0]; } }; const el =Hello Javascript
; console.log(el);
上面代碼添加了一個(gè)React對(duì)象,并在其中添加一個(gè)createElement方法,現(xiàn)在再執(zhí)行一下看看打印出什么:
由打印結(jié)果可以看出,jsx在使用React.createElement方法轉(zhuǎn)譯時(shí),createElement方法應(yīng)該是這樣的:
createElement({ elementName, attributes, children });
elementName: dom對(duì)象的標(biāo)簽名 比如div、span等等
attributes: 當(dāng)前dom對(duì)象的屬性集合 比如class、id等等
children: 所有子節(jié)點(diǎn)
現(xiàn)在我們改寫一下createElement方法,讓key的名稱簡單一點(diǎn):
const React = { createElement: function({ elementName, attributes, children }) { return { tag: elementName, attrs: attributes, children }; } };
現(xiàn)在可以看到打印結(jié)果是:
我們?cè)俅蛴€(gè)復(fù)雜點(diǎn)的DOM結(jié)構(gòu):
const el = (Hello JavaScript); console.log(el);
和我們想要的結(jié)構(gòu)一樣。
其實(shí)上面打印出來的就是虛擬DOM,現(xiàn)在我們要做的就是如何把虛擬DOM轉(zhuǎn)成真正的DOM對(duì)象并顯示在瀏覽器上。
要想將虛擬dom轉(zhuǎn)成真實(shí)dom并渲染到頁面上,就需要調(diào)用ReactDOM.render,比如:
ReactDOM.render(Hello World
, document.getElementById("root"));
這段代碼轉(zhuǎn)換后的樣子:
ReactDOM.render( React.createElement("h1", null, "Hello World"), document.getElementById("root") );
這時(shí),react會(huì)將Hello World
掛載到id為root的dom下,從而在頁面上顯示出來。
現(xiàn)在我們實(shí)現(xiàn)render方法:
function render(vnode, container) { const dom = createDom(vnode); //將vnode轉(zhuǎn)成真實(shí)DOM container.appendChild(dom); }
上面代碼中先調(diào)用createDom將虛擬dom轉(zhuǎn)成真實(shí)DOM,然后掛載到container下。
我們來實(shí)現(xiàn)createDom方法:
function createDom(vnode) { if (vnode === undefined || vnode === null || typeof vnode === "boolean") { vnode = ""; } if (typeof vnode === "string" || typeof vnode === "number") { return document.createTextNode(String(vnode)); } const dom = document.createElement(vnode.tag); //設(shè)置屬性 if (vnode.attrs) { for (let key in vnode.attrs) { const value = vnode.attrs[key]; setAttribute(dom, key, value); } } //遞歸render子節(jié)點(diǎn) vnode.children.forEach(child => render(child, dom)); return dom; }
由于屬性的種類比較多,我們抽出一個(gè)setAttribute方法來設(shè)置屬性:
function setAttribute(dom, key, value) { //className if (key === "className") { dom.setAttribute("class", value); //事件 } else if (/onw+/.test(key)) { key = key.toLowerCase(); dom[key] = value || ""; //style } else if (key === "style") { if (typeof value === "string") { dom.style.cssText = value || ""; } else if (typeof value === "object") { // {width:"",height:20} for (let name in value) { //如果是數(shù)字可以忽略px dom.style[name] = typeof value[name] === "number" ? value[name] + "px" : value[name]; } } //其他 } else { dom.setAttribute(key, value); } }
現(xiàn)在render方法已經(jīng)完整的實(shí)現(xiàn)了,我們將創(chuàng)建ReactDOM對(duì)象,將render方法掛上去:
const ReactDOM = { render: function(vnode, container) { container.innerHTML = ""; render(vnode, container); } };
這里在調(diào)用render之前加了一句container.innerHTML = "",就不解釋了,相信大家都明白。
那么萬事具備,我們來測(cè)試一下,直接上一個(gè)比較復(fù)雜的dom結(jié)構(gòu)并加上屬性:
const element = (alert(1)} style={{ color: "red", fontSize: 30 }} > Hello javascript!); ReactDOM.render(element, document.getElementById("root"));
打開頁面,是我們想要的結(jié)果:
再看看控制臺(tái)的dom:
很完美,這是我們想要的東西
后語該demo代碼在這里喲~~
本文敘述了JSX和虛擬DOM,以及將虛擬DOM轉(zhuǎn)成真實(shí)DOM的過程,后面的文章會(huì)繼續(xù)敘述react中的組件、生命周期、diff算法和異步setState,敬請(qǐng)期待~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/94892.html
摘要:市面上竟然擁有多個(gè)虛擬庫。虛擬庫,就是出來后的一種新式庫,以虛擬與算法為核心,屏蔽操作,操作數(shù)據(jù)即操作視圖。及其他虛擬庫已經(jīng)將虛擬的生成交由與處理了,因此不同點(diǎn)是,虛擬的結(jié)構(gòu)與算法。因此虛擬庫是分為兩大派系算法派與擬態(tài)派。 去哪兒網(wǎng)迷你React是年初立項(xiàng)的新作品,在這前,去哪兒網(wǎng)已經(jīng)深耕多年,擁有QRN(react-native的公司制定版),HY(基于React的hybird方案)...
摘要:時(shí)間選擇的表盤其實(shí)有兩個(gè),一個(gè)是小時(shí)的選擇,另一個(gè)則是分鐘的選擇。也就是說,第一步選擇小時(shí),第二部選擇分鐘它是一個(gè)小時(shí)制的時(shí)間選擇器。而則用于處理拖拽事件,標(biāo)記著當(dāng)前是否處于被拖拽狀態(tài)。 本文的源碼全部位于github項(xiàng)目倉庫react-times,如果有差異請(qǐng)以github為準(zhǔn)。最終線上DEMO可見react-times github page 文章記錄了一次創(chuàng)建獨(dú)立React組件...
摘要:是一個(gè)看起來像的語法擴(kuò)展。有人覺得看起來太怪異了,但是我覺得是一個(gè)偉大的嘗試,是科學(xué)進(jìn)步的表現(xiàn),我們不應(yīng)該對(duì)他有任何偏見。所以有一個(gè)口號(hào),就是所以,的是一個(gè)偉大的嘗試,我們應(yīng)該擁抱。 原文: http://eyasweb.com/#/blog/detail/12 react 帶來了新的語法,JSX。是一個(gè)看起來像XML的JavaScript語法擴(kuò)展。 有些同學(xué)因?yàn)椴幌矚g或不習(xí)慣JSX語...
摘要:是一個(gè)看起來像的語法擴(kuò)展。有人覺得看起來太怪異了,但是我覺得是一個(gè)偉大的嘗試,是科學(xué)進(jìn)步的表現(xiàn),我們不應(yīng)該對(duì)他有任何偏見。所以有一個(gè)口號(hào),就是所以,的是一個(gè)偉大的嘗試,我們應(yīng)該擁抱。 原文: http://eyasweb.com/#/blog/detail/12 react 帶來了新的語法,JSX。是一個(gè)看起來像XML的JavaScript語法擴(kuò)展。 有些同學(xué)因?yàn)椴幌矚g或不習(xí)慣JSX語...
閱讀 3943·2021-09-10 11:22
閱讀 2449·2021-09-03 10:30
閱讀 3738·2019-08-30 15:55
閱讀 2061·2019-08-30 15:44
閱讀 907·2019-08-30 15:44
閱讀 650·2019-08-30 14:04
閱讀 3127·2019-08-29 17:18
閱讀 1339·2019-08-29 15:04