1.Virtual DOM模型負責Virtual DOM底層框架的構建工做,它擁有一整套的Virtual DOM標籤,
並負責虛擬節點及其屬性的構建,更新,刪除等工做.
2.其實,構建一套簡易Virtual DOM模型並不複雜,它只須要具有一個DOM標籤所需的基本元素便可.node
{ // 標籤名 tagName: 'div', // 屬性 properties: { // 樣式 style: {} }, // 子節點 children: [], // 惟一標識 key: 1 }
3.Virtual DOM中的節點稱爲ReactNode,它分爲3種類型:ReactElement,ReactFragment,ReactText.
其中,ReactElement又分爲ReactComponentElement和ReactDOMElement.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方法app
// 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,這就是初始化組件的入口函數,
它經過判斷node類型來區分不一樣組件的入口.框架
// 初始化組件入口 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爲了保持渲染的一致性,
將其封裝爲文本組件ReactDOMTextComponent.dom
1.Virtual DOM模型涵蓋了幾乎全部的原生DOM標籤,如<div>,<p>,<span>等.
當開發者使用React時,此時的<div>並非原生的<div>標籤,他實際上是React生成的
Virtual DOM對象,只不過標籤名稱相同罷了.函數
_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; }