React系列文章:无状态组件生成真实DOM结点
在上一篇文章中,我们总结并模拟了JSX生成真实DOM结点的过程,今天接着来介绍一下无状态组件的生成过程。 先以下面一段简单的代码举例: const Greeting = function ({name}) { return <div>{`hello ${name}`}</div>; }; const App = <Greeting name="scott"/>; console.log(App); ReactDOM.render(App,document.getElementById(‘root‘)); 可以看出, var Greeting = function Greeting(_ref) { var name = _ref.name; return React.createElement( "div",null,"hello " + name ); }; var App = React.createElement(Greeting,{ name: "scott" }); console.log(App); ReactDOM.render(App,document.getElementById(‘root‘)); 我们看到,调用 下图是我们运行上面代码之后,打印出的 我们再来看一个稍微复杂些的例子: const Greeting = function ({name}) { return ( <div>{`hello ${name}`}</div> ); }; const Container = function ({children}) { return ( <div className="container"> {children} </div> ); }; const App = ( <Container> <Greeting name="scott"/> <Greeting name="jack"/> <Greeting name="john"/> </Container> ); console.log(App); ReactDOM.render(App,document.getElementById(‘root‘)); 在上面代码中,我们定义了两个无状态组件,其中 现在再来看看编译后的代码结构: var Greeting = function Greeting(_ref) { var name = _ref.name; return React.createElement( "div","hello " + name ); }; var Container = function Container(_ref2) { var children = _ref2.children; return React.createElement( "div",{ className: "container" },children ); }; var App = React.createElement( Container,React.createElement(Greeting,{ name: "scott" }),{ name: "jack" }),{ name: "john" }) ); console.log(App); ReactDOM.render(App,document.getElementById(‘root‘)); 这次我们主要观察 接下来,我们要改进一下之前实现的 先来看看 const React = { // 创建DOM描述对象 即虚拟DOM createElement(type,props,...children) { let propsChildren = children; // 组件参数的props.children本身是数组 // 所以调用组件函数时这里需要特殊处理 if (Array.isArray(children[0])) { propsChildren = children[0]; } // 结点 let vnode = { type,props: { ...props,children: propsChildren,} }; // 挂载组件函数体的虚拟DOM if (typeof type === ‘function‘) { vnode.body = type({ ...props,children,}); } return vnode; } }; 上面的代码主要对组件做了特殊处理。如果当前处理对象是组件,则对应的 现在,我们运行程序,看看上面代码生成的虚拟DOM结构: 最后,再来看看 const ReactDOM = { // 渲染真实DOM render(vnode,container) { let realDOM = this.generateDOM(vnode); container.appendChild(realDOM); },// 获取真实DOM generateDOM(vnode) { if (typeof vnode.type === ‘function‘) { // 将组件函数体的虚拟DOM生成真实DOM return this.generateDOM(vnode.body); } let elem = document.createElement(vnode.type); // 特殊key值映射 let specialKeyMap = { className: ‘class‘,fontSize: ‘font-size‘,}; let {props} = vnode; // 设置DOM属性 props && Object.keys(props).forEach(key => { if (key === ‘children‘) { // 处理子节点 props.children.forEach(child => { if (typeof child === ‘string‘) { // 纯内容节点 elem.appendChild(document.createTextNode(child)); } else { // DOM节点 elem.appendChild(this.generateDOM(child)); } }); } else if (key === ‘style‘) { // 设置样式属性 let styleObj = props.style; let styleItems = []; Object.keys(styleObj).forEach(styleKey => { styleItems.push(`${specialKeyMap[styleKey] || styleKey}:${styleObj[styleKey]}`); }); elem.setAttribute(‘style‘,styleItems.join(‘;‘)); } else { // 设置其他属性 elem.setAttribute(specialKeyMap[key] || key,props[key]); } }); return elem; } }; 上面代码中改动较小,我们只添加了几行针对组件的处理逻辑,如果是组件函数,则将函数体的虚拟DOM生成真实DOM。 最后,我们来看看最终生成的DOM结构: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |