重新认识react-vdom

265 阅读1分钟

本文是读完你不知道的Virtual DOM(一):Virtual Dom介绍后的一篇实操笔记

vdom实质上是个js对象,提供了跨平台的可能
jsx -> 编译器 -> vdom(js对象) -> createElement(vdom)

当vdom是纯文本或者数字时,typeof vdom === 'string' 或者 typeof vdom == 'number'

  • jsx的编译过程
    • 使用babel插件plugin-transform-react-jsx,jsx编译能得到下面object(包含tag标签,props属性,children子节点)
        // 下面的h函数可以在babelrc中定义方法名
        {
            h(
                tag: 'div',
                props: {},
                'hello, world'
                children: [
                    h(
                        tag: 'div',
                        props: {},
                        '1',
                        children:[]
                    ),
                    h(
                        tag: 'div',
                        props: {},
                        '2',
                        children: []
                    )
                ]
            )
        }
        // .babelrc
        {
            "plugins": [
                [
                  "@babel/plugin-transform-react-jsx", {
                      "pragma": "h"  // 方法名
                    }
                ]
            ]
        }
        // h方法
        function h(tag, props, ...children) {
          return {
            tag: tag,
            props: props || [],
            children
          }
        }
        // 最终得到的object
        {
            tag: 'div',
            props: {},
            children: [
                'hello, world',
                {
                    tag: 'div',
                    props: {},
                    children:[
                        '1',
                    ]
                },
                {
                    tag: 'div',
                    props: {},
                    children: [
                        '2',
                    ]
                }
            ]
        }
    
  • vdom 转化成真实DOM
// createElement将vdom转化为真实dDOM
function createElement(vdom) {
  // 字符串和数字文本直接返回dom文本
  if (typeof vdom === 'string' || typeof vdom === 'number') {
    return document.createTextNode(vdom);
  }

  const element = document.createElement(vdom.tag);
  // DOM节点设置属性
  setProps(element, vdom.props);
  // forEach的callback this是window,需要给appendChild的this指向当前节点,不然会有报错
  vdom.children.map(createElement).forEach(element.appendChild.bind(element));
  return element;
}

function setProps(element, props) {
  for (item in props) {
    element.setAttribute(item, props[item]);
  }
}
  • 真实DOM的挂载
// JSX
function View() {
  return (
    <div>
      hello, world
      <div>1</div>
      <div>2</div>
    </div>
  )
}
// 渲染挂载
function render() {
  const vdom = View(); // 会编译成vdom
  const nodeElemnt = createElement(vdom); // 生成真实DOM
  document.getElementById('root').appendChild(nodeElemnt); // 真实DOM的挂载
}

以上实操代码可在git上找到

参考文章

你不知道的Virtual DOM(一):Virtual Dom介绍