解读React源码(二):Virtual DOM模型
Virtual DOM模型1.Virtual DOM模型负责Virtual DOM底层框架的构建工作,它拥有一整套的Virtual DOM标签, { // 标签名 tagName: 'div',// 属性 properties: { // 样式 style: {} },// 子节点 children: [],// 唯一标识 key: 1 } 3.Virtual DOM中的节点称为ReactNode,它分为3种类型:ReactElement,ReactFragment,ReactText. 创建React元素// 输入jsx const app = <Nav color="blue"><Profile>click</Profile></Nav>; // 输出js const app = React.createElement( Nav,{color: 'blue'},React.createElement(Profile,null,'click') ); 通过jsx创建的虚拟元素最终会被编译成调用React的createElement方法 // createElement只是做了简单修正,返回一个ReactElement实例对象 // 也就是虚拟元素的实例 ReactElement.createElement = function(type,config,children) { // 初始化参数 var propName; var props = {}; var key = null; var ref = null; var self = null; var source = null; // 如果存在config,则提取里面的内容 if (config != null) { ref = config.ref === undefined ? null : config.ref; key = config.key === undefined ? null : '' + config.key; self = config._self === undefined ? null : config._self; source = config._source === undefined ? null : config._source; // 复制config里的内容到props(id和className等) for (propName in config) { if (config.hasOwnProperty(propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { props[propName] = config[propName]; } } } // 处理children,全部挂载到props的children属性上,如果只有一个参数,直接赋值给children // 否则做合并处理 var childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { var childArray = Array(childrenLength); for (var i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } props.children = childArray; } // 如果某个prop为空且存在默认的prop,则将默认prop赋给当前的prop if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { if (typeof props[propName] === 'undefined') { props[propName] = defaultProps[propName] } } } // 返回一个ReactElement实例对象 return ReactElement(type,key,ref,self,source,ReactCurrentOwner.current,props); } 初始化组件入口1.当使用React创建组件时,首先会调用instantiateReactComponent,这就是初始化组件的入口函数, // 初始化组件入口 function instantiateReactComponent(node,parentCompositeType) { var instance; // 空组件 (ReactEmptyComponent) if (node === null || node === false) { instance = ReactEmptyComponent.create(instantiateReactComponent); } if (typeof node === 'object') { var element = node; if (typeof element.type === 'string') { // DOM标签 (ReactDOMComponent) instance = ReactNativeComponent.createInternalComponent(element); } else if (isInternalComponentType(element.type)) { // 不是字符串表示的自定义组件暂无法使用,此处将不做组件初始化操作 instance = new element.type(element); } else { // 自定义组件 instance = new ReactCompositeComponentWrapper(); } } else if (typeof node === 'string' || typeof node === 'number') { // 字符串或数字 instance = ReactNativeComponent.createInstanceForText(node); } else { // 不做处理 } // 设置实例 instance.construct(node); // 初始化参数 instance._mountIndex = 0; instance._mountImage = null; return instance; } 文本组件1.当node类型为文本节点时是不算Virtual DOM元素的,但React为了保持渲染的一致性, DOM标签组件1.Virtual DOM模型涵盖了几乎所有的原生DOM标签,如<div>,<p>,<span>等. _createOpenTagMarkupAndPutListeners: function(transaction,props) { var ret = '<' + this._currentElement.type; // 拼凑出属性 for (var propKey in props) { var propValue = props[propKey]; if (registrationNameModules.hasOwnProperty(propKey)) { // 针对当前的节点添加事件代理 if (propValue) { enqueuePutListener(this,propKey,propValue,transaction); } } else { if (propKey === STYLE) { if (propValue) { // 合并样式 propValue = this._previousStyleCopy = Object.assign({},props.style); } propValue = CSSPropertyOperations.createMarkupForStyles(propValue,this); } // 创建属性标识 var markup = null; if (this._tag != null && isCustomComponent(this._tag,props)) { markup = DOMPropertyOperations.createMarkupForProperty(propKey,propValue); } if (markup) { ret += ' ' + markup; } } } // 对于静态页面,不需要设置react-id,这样可以节省大量字节 if (transaction.renderToStaticMarkup) { return ret; } // 设置reactid if (!this._nativeParent) { ret += ' ' + DOMPropertyOperations.createMarkupForRoot(); } ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID); return ret; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |