文章首发于个人博客 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 的一个递归方法函数
相关文章