文章首發於個人博客 https://github.com/mcuking/bl...相關代碼請查閱 https://github.com/mcuking/bl...css
能夠經過 babel 實現將 JSX 轉化爲原生 js,例如:html
const hw = <div>Hello World</div> const hw = React.createElement('div', null, "Hello World")
以上兩行是等效的,因此本項目無需關心 JSX 語法node
react 中 virtual-dom 的概念,即便用一個 js 對象——vnode 來描述 DOM 節點,而後根據 vnode 進行實際操做 DOM 節點,從而渲染出 DOM 樹。
其中,vnode 對象有 3 個屬性:react
如下就是如何經過 createElement 函數,從 JSX 轉化後的代碼中生成咱們所要的 vnode:git
// 負責生成 vnode export default function createElement(comp, props, ...args) { let children = [] for (let i = 0; i < args.length; i++) { if (args[i] instanceof Array) { children = children.concat(args[i]) } else { children.push(args[i]) } } return { nodeName: comp, props: props || {}, children } }
如下是咱們使用 react 寫的一個組件github
class Animal extends Component { render() { return ( <Pet/> ) } } class Pet extends Component { render() { return ( <Cat/> ) } } class Cat extends Component { render() { return ( <div>i am a cat</div> ) } } render(<Animal/>, document.getElementById('container'))
最終會渲染爲 i am a cat
渲染過程是:渲染 Animal 的 Vnode -> 渲染 Pet 的 Vnode -> 渲染 Cat 的 Vnode
這是一個遞歸的過程:遞歸的終止條件是——渲染 html 標籤:babel
代碼以下:app
function render(vnode, parent) { let dom if(typeof vnode == "string") { dom = document.createTextNode(vnode) parent.appendChild(dom) } else if(typeof vnode.nodeName == "string") { dom = document.createElement(vnode.nodeName) setAttrs(dom, vnode.props) parent.appendChild(dom) for(let i = 0; i < vnode.children.length; i++) { render(vnode.children[i], dom) } } else if (typeof vnode.nodeName == "function") { let func = vnode.nodeName let inst = new func(vnode.props) let innerVnode = inst.render() render(innerVnode, parent) } } // 設置 DOM 節點屬性 function setAttrs(dom, props) { for (let k in props) { // 屬性爲 className 時,改成 class if (k === 'className') { dom.setAttribute('class', props[k]) continue } // 屬性爲 style 時 if (k === 'style') { if (typeof props[k] === 'string') { dom.style.cssText = props[k] } if (typeof props[k] === 'object') { for (let v in props[k]) { dom.style[v] = props[k][v] } } continue } // 屬性爲 on 開頭的綁定的事件 if (k[0] === 'o' && k[1] === 'n') { dom.addEventListener(k.substring(2).toLowerCase(), props[k], false) continue } // 其他屬性直接賦值 dom.setAttribute(k, props[k]) } }
總結一下:dom
render —— 是根據生成的 vnode, 渲染到實際的 dom 的一個遞歸方法函數
相關文章