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