本文是读完你不知道的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上找到