本文分爲css
npm i -g create-react-app
create-react-app my-app
cd my-app
npm start
複製代碼
而且把src中其餘文件都刪除,留下index.js就能夠接下來了前端
首先要肯定咱們vnode對象的屬性; type:標籤名,attrs:屬性名,children:子元素node
實例: react
那麼根據上面咱們須要的vnode結果,咱們去寫建立vnode的函數 createElement(type, attrs, children)git
src/index.js
import { createElement } from './element'
let virtualDom = createElement('ui', { class: 'li-group' }, [
createElement('li', { class: 'item' }, ['a']),
createElement('li', { class: 'item' }, ['b'])
])
複製代碼
接下來咱們開始具體去寫createElement函數,咱們先在src下新建一個element.js文件github
src/elment.js
class Element {
constructor(type, attrs, children) {
this.type = type
this.attrs = attrs
this.children = children
}
}
function createElement(type, attrs, children) {
return new Element(type, attrs, children)
}
export { createElement }
複製代碼
如今咱們已經能夠從上面打印出virtualDom的數據結構了,那麼接下來就是將virtualDom經過render函數去構建成真實的dom算法
render(virtualDom, target) target:添加的目標節點npm
src/index.js
import { render } from './element'
let el = render(virtualDom)
複製代碼
src/element.js
function render(virtualDom){
const { type, attrs, children } = virtualDom
let el = document.createElement(type)
// 掛載屬性
for(let key in attrs){
setAttr(el, key, attrs[key])
}
// 建立子節點
children.forEach(child=>{
if(child instanceof Element){
// 節點
el.appendChild(render(child))
}else{
// 文本
let textNode = document.createTextNode(child)
el.appendChild(textNode)
}
})
return el
}
function setAttr(node, key, value){
switch(key){
case 'value': // input textarea
if(node.tagName.toUpperCase() === 'INPUT' || node.tagName.toUpperCase() === 'TEXTAREA'){
node[key] = value
} else{
node.setAttribute(key, value)
}
break;
case 'style':
node.style.cssText = value
break;
default:
node.setAttribute(key, value)
break;
}
}
複製代碼
那麼如今咱們終於能夠將Dom渲染到頁面中了bash
src/index.js
import { renderDom } from './element'
renderDom(el, document.getElementById('root'))
複製代碼
src/element.js
function renderDom(el, target){
target.appendChild(el)
}
複製代碼
github: github.com/XueMary/my-…數據結構
vnode已經完成了,那麼接下來就還有數據變動後的 diff 算法 和 diff 算法計算出的變動內容 patch。 數據變動後會產生新的vnode, diff會對比兩份 vnode 查到其中的變動,再將這些變動經過patch函數去修改真實dom
網上不少人說虛擬動效率高,性能好。
開始分析了:
一、什麼虛擬dom通過diff算法實現了dom的最小變化,局部刷新(這句話每錯),可是和性能不要緊,你手動去操做dom,看看控制檯是否是也只有你改變的dom元素刷新了,手工操做自己就是最小變化,框架還要通過diff,那麼框架爲何要diff,由於不diff,那他就得把整個頁面出現渲染了。
二、另外一種說法就更唬人點了。什麼js線程和渲染線程是兩個部門,跨部門交流固然耗性能,js去更新 虛擬dom是js和js間的溝通,搞的好像更新了虛擬dom樹後不用去操做真實dom同樣了。比手工操做還多了一遍操做
回到框架自己,如今前端是數據驅動視圖,是爲了讓使用者只關注數據自己,對dom的增刪改查就都被隱藏在了框架中,框架自己也須要這麼一份vnode的描述,來講明如今的node結構是怎麼的,否則他也不知道哪裏被改變了,也就沒法幫咱們去修改真實dom了
這纔是維護一份虛擬dom的做用