May.js 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147
  1. 'use strict';
  2. /**
  3. *
  4. * @param {*} type dom类型或func
  5. * @param {*} props dom属性
  6. * @param {*} children 子节点
  7. */
  8. function createElement(type, config, children) {
  9. var props = {};
  10. var key = null;
  11. var ref = null;
  12. var mtype = null;
  13. var getContext = null;
  14. var len = arguments.length - 2;
  15. //0代表没有ref 1代表ref为func 2为string
  16. var refType = 0;
  17. //既然render的时候都需要判断下type 是fun或string
  18. //那把这一步提前 比render循环里判断更好些;
  19. var _type = typeof type;
  20. switch (_type) {
  21. case 'string': //HtmlElement 1 SVG 3
  22. mtype = type !== 'svg' ? 1 : 3;
  23. break;
  24. case 'function': //component 或statelessComponent
  25. mtype = 2;
  26. //如果有contextTypes代表该组件可以取context
  27. type.contextTypes && (getContext = true);
  28. break;
  29. }
  30. if (config) {
  31. key = config.key !== void 0 ? ('' + config.key) : null;
  32. ref = config.ref || null;
  33. if (typeof ref === 'number') {
  34. ref = '' + ref;
  35. }
  36. if (ref) {
  37. var _refType = typeof ref;
  38. switch (_refType) {
  39. case 'function':
  40. refType = 1;
  41. break;
  42. case 'string':
  43. refType = 2;
  44. break;
  45. }
  46. }
  47. for (var i in config) {
  48. if (i !== 'key' && i != 'ref') {
  49. props[i] = config[i];
  50. }
  51. }
  52. }
  53. var defaultProps = type.defaultProps;
  54. if (defaultProps) {
  55. for (var propName in defaultProps) {
  56. if (props[propName] === void 666) {
  57. props[propName] = defaultProps[propName];
  58. }
  59. }
  60. }
  61. if (len > 1) {
  62. var array = new Array();
  63. for (var i = 0; i < len; i++) {
  64. var c = arguments[i + 2];
  65. if (!Array.isArray(c)) {
  66. array.push(c);
  67. } else {
  68. c.forEach(function (item) {
  69. array.push(item);
  70. });
  71. }
  72. }
  73. props.children = array;
  74. } else if (len === 1) {
  75. props.children = children;
  76. }
  77. return new Vnode(type, key, ref, props, mtype, getContext, refType);
  78. }
  79. /**
  80. *
  81. * @param {*} type
  82. * @param {*} key
  83. * @param {*} ref
  84. * @param {*} self
  85. * @param {*} source
  86. * @param {*} owner
  87. * @param {*} props
  88. */
  89. var Vnode = function (type, key, ref, props, mtype, getContext, refType) {
  90. this.type = type;
  91. this.key = key;
  92. this.ref = ref;
  93. this.props = props;
  94. this.$$typeof = 1;
  95. this.mtype = mtype;
  96. //之前是直接赋在vnode上 多了之后容易混
  97. //单独新建个对象存放各种信息
  98. this.mayInfo = {};
  99. this.getContext = getContext;
  100. this.refType = refType;
  101. };
  102. // function isArray(o) {
  103. // return Object.prototype.toString.call(o) == '[object Array]';
  104. // }
  105. //文本节点重复利用
  106. var recyclables={
  107. '#text':[]
  108. };
  109. function mergeState(instance) {
  110. var newState;
  111. var prevState = instance.state;
  112. if (instance.mayInst.mergeStateQueue && instance.mayInst.mergeStateQueue.length > 0) {
  113. var queue = instance.mayInst.mergeStateQueue;
  114. var newState = extend({}, prevState);
  115. for (var i = 0; i < queue.length; i++) {
  116. var s = queue[i];
  117. if (s && s.call) {
  118. s = s.call(instance, newState, instance.nextProps || instance.props);
  119. }
  120. newState = extend(newState, s);
  121. }
  122. instance.mayInst.mergeStateQueue.length = 0;
  123. } else {
  124. newState = prevState;
  125. }
  126. return newState;
  127. }
  128. // export function eventProxy(e) {
  129. // return this._listener[e.type](e);
  130. // }
  131. function extend(target, src) {
  132. for (var key in src) {
  133. if (src.hasOwnProperty(key)) {
  134. target[key] = src[key];
  135. }
  136. }
  137. return target;
  138. }
  139. /**
  140. * 寄生组合式继承
  141. * @param {*} target
  142. * @param {*} superClass
  143. */
  144. function inherits(target, superClass) {
  145. function b() { }
  146. b.prototype = superClass.prototype;
  147. var fn = target.prototype = new b();
  148. fn.constructor = target;
  149. return fn;
  150. }
  151. var Refs = {
  152. //当子component含有ref的时候,需要把对应的instance或dom添加到 父component的refs属性中
  153. //如果在mountComponent中做这样的操作需要每一层都要添加owner 放在外面更好些;
  154. currentOwner: null,
  155. //开始render时isRoot为true,方便ref定位最顶端节点
  156. isRoot: false,
  157. attachRef: function (vnode, hostNode) {
  158. if (vnode.refType === 1) { //func
  159. hostNode.mayInst && hostNode.mayInst.stateless && (hostNode = null);
  160. lifeCycleQueue.push(vnode.ref.bind(vnode, hostNode));
  161. } else if (vnode.refType === 2) { //string
  162. this.currentOwner.refs[vnode.ref] = hostNode;
  163. }
  164. }
  165. };
  166. //mayQueue 保存render过程中的各种事件队列
  167. var mayQueue = {
  168. dirtyComponentsQueue: [], //setState 需要diff的component队列
  169. callbackQueue: [], //回调队列 setState 中的事件回调
  170. lifeCycleQueue: [], //生命周期过程中的回调队列 DidUpdate DidMount ref回调
  171. isInEvent: false, //是否在触发事件 回调事件中的setstate合并触发
  172. clearQueue: clearQueue,
  173. flushUpdates: flushUpdates,
  174. };
  175. //存放生命周期中的 DidMount DidUpdate以及ref回调
  176. var lifeCycleQueue = mayQueue.lifeCycleQueue;
  177. /**
  178. * 清空回调队列
  179. * @param {*} mayQueue
  180. */
  181. function clearQueue() {
  182. //ComponentDidMount
  183. clearLifeCycleQueue();
  184. //如有有dirty Component diff
  185. flushUpdates();
  186. //setState传入的回调函数
  187. clearCallbackQueue();
  188. }
  189. function flushUpdates() {
  190. var instance;
  191. var i = 0;
  192. //如果在当前生命周期的DidMount调用setState 放到下一生命周期处理
  193. mayQueue.dirtyComponentsQueue = mayQueue.dirtyComponentsQueue.sort(sortComponent);
  194. while (instance = mayQueue.dirtyComponentsQueue.shift()) {
  195. if (i++ === 0) {
  196. Refs.isRoot = true;
  197. }
  198. if (instance.mayInst.dirty) {
  199. //如果C是脏组件diff 如果其在diff过程中子组件也需要diff diff之后
  200. //子组件_dirty会为false 没必要再diff一次;
  201. reRender(instance);
  202. }
  203. if (instance) {
  204. //diff之后组件的状态返回0
  205. instance.mayInst.lifeState = 0;
  206. }
  207. }
  208. //ComponentDidUpdate
  209. clearLifeCycleQueue();
  210. //防止setState currentOwner混乱
  211. Refs.currentOwner = null;
  212. }
  213. function clearLifeCycleQueue() {
  214. //先清空 生命周期 ref 的回调函数
  215. if (mayQueue.lifeCycleQueue && mayQueue.lifeCycleQueue.length > 0) {
  216. var callback;
  217. //其实ref很像生命周期函数,它比较特殊的地方在于vnode.type='div'之类的vnode
  218. //其string ref要指向其真实dom func ref也是回调真实的dom 其它的都是回调instance
  219. //vnode.type='div'之类的ref特殊处理;剩余的就和生命周期很像了;
  220. while (callback = mayQueue.lifeCycleQueue.shift()) {
  221. callback();
  222. }
  223. }
  224. }
  225. function clearCallbackQueue() {
  226. //再清空 setState传入的回调函数
  227. if (mayQueue.callbackQueue && mayQueue.callbackQueue.length > 0) {
  228. var callback;
  229. mayQueue.callbackQueue = mayQueue.callbackQueue.sort(sortCallback);
  230. while (callback = mayQueue.callbackQueue.shift()) {
  231. callback();
  232. }
  233. }
  234. }
  235. function sortCallback(a, b) {
  236. return a._mountOrder - b._mountOrder;
  237. }
  238. function sortComponent(a, b) {
  239. return a.mayInst.mountOrder - b.mayInst.mountOrder;
  240. }
  241. var globalEvent = {
  242. };
  243. var eventHooks = {}; //用于在元素上绑定特定的事件
  244. var document$1 = window.document;
  245. var isTouch = "ontouchstart" in document$1;
  246. function dispatchEvent(e, type, end) {
  247. e = new SyntheticEvent(e);
  248. if (type) {
  249. e.type = type;
  250. }
  251. var _type = e.type;
  252. //全局的一个标识 在事件中setState应当合并
  253. mayQueue.isInEvent = true;
  254. //onClickCapture 在捕获阶段触发
  255. var captured = _type + 'capture';
  256. var eventCollect = bubbleEvent(e.target, end || document$1);
  257. //先触发捕获
  258. triggerEventFlow(e, eventCollect, captured);
  259. if (!e._stopPropagation) {
  260. //触发冒泡
  261. triggerEventFlow(e, eventCollect.reverse(), _type);
  262. }
  263. mayQueue.isInEvent = false;
  264. //在事件中合并state之后 触发reRender
  265. mayQueue.clearQueue();
  266. }
  267. /**
  268. * 自己冒泡,收集冒泡过程中的所有事件
  269. * @param {*event target} from
  270. * @param {*end || document} end
  271. */
  272. function bubbleEvent(from, end) {
  273. var collect = [];
  274. do {
  275. if (from === end) {
  276. break;
  277. }
  278. var event = from._listener;
  279. if (event) {
  280. collect.push({
  281. dom: from,
  282. events: event
  283. });
  284. }
  285. } while ((from = from.parentNode) && from.nodeType === 1);
  286. // target --> parentNode --> body --> html
  287. return collect;
  288. }
  289. function triggerEventFlow(e, collect, prop) {
  290. for (var i = collect.length; i--;) {
  291. var eObj = collect[i];
  292. var fn = eObj.events[prop];
  293. if (isFn(fn)) {
  294. e.currentTarget = eObj.dom;
  295. fn.call(eObj.dom, e);
  296. if (e._stopPropagation) {
  297. break;
  298. }
  299. }
  300. }
  301. }
  302. var eventLowerCache = {
  303. onClick: "click",
  304. onChange: "change",
  305. onWheel: "wheel"
  306. };
  307. var rcapture = /Capture$/;
  308. function getBrowserName(onStr) {
  309. var lower = eventLowerCache[onStr];
  310. if (lower) {
  311. return lower;
  312. }
  313. var camel = onStr.slice(2).replace(rcapture, "");
  314. lower = camel.toLowerCase();
  315. eventLowerCache[onStr] = lower;
  316. return lower;
  317. }
  318. function addEvent(name) {
  319. if (!globalEvent[name]) {
  320. globalEvent[name] = true;
  321. addDocumentEvent(document$1, name, dispatchEvent);
  322. }
  323. }
  324. function addDocumentEvent(el, name, fn, bool) {
  325. if (el.addEventListener) {
  326. el.addEventListener(name, fn, bool || false);
  327. } else if (el.attachEvent) {
  328. el.attachEvent('on' + name, fn);
  329. }
  330. }
  331. function SyntheticEvent(event) {
  332. if (event.nativeEvent) {
  333. return event;
  334. }
  335. if (!this.target) {
  336. this.target = event.srcElement;
  337. }
  338. for (var i in event) {
  339. if (!eventProto[i]) {
  340. this[i] = event[i];
  341. }
  342. }
  343. this.timeStamp = new Date() - 0;
  344. this.nativeEvent = event;
  345. }
  346. function createHandle(name, fn) {
  347. return function (e) {
  348. if (fn && fn(e) === false) {
  349. return;
  350. }
  351. dispatchEvent(e, name);
  352. };
  353. }
  354. if (isTouch) {
  355. eventHooks.click = noop;
  356. eventHooks.clickcapture = noop;
  357. }
  358. var changeHandle = createHandle("change");
  359. var doubleClickHandle = createHandle("doubleclick");
  360. //react将text,textarea,password元素中的onChange事件当成onInput事件
  361. eventHooks.changecapture = eventHooks.change = function (dom) {
  362. if (/text|password/.test(dom.type)) {
  363. addDocumentEvent(document$1, "input", changeHandle);
  364. }
  365. };
  366. eventHooks.doubleclick = eventHooks.doubleclickcapture = function () {
  367. addDocumentEvent(document$1, "dblclick", doubleClickHandle);
  368. };
  369. var eventProto = (SyntheticEvent.prototype = {
  370. preventDefault: function () {
  371. var e = this.nativeEvent || {};
  372. e.returnValue = this.returnValue = false;
  373. if (e.preventDefault) {
  374. e.preventDefault();
  375. }
  376. },
  377. fixHooks: function () { },
  378. stopPropagation: function () {
  379. var e = this.nativeEvent || {};
  380. e.cancleBubble = this._stopPropagation = true;
  381. if (e.stopPropagation) {
  382. e.stopPropagation();
  383. }
  384. },
  385. persist: noop,
  386. stopImmediatePropagation: function () {
  387. this.stopPropagation();
  388. this.stopImmediate = true;
  389. },
  390. toString: function () {
  391. return "[object Event]";
  392. }
  393. });
  394. Object.freeze ||
  395. (Object.freeze = function (a) {
  396. return a;
  397. });
  398. function isFn(obj) {
  399. return Object.prototype.toString.call(obj) === "[object Function]";
  400. }
  401. function noop() { }
  402. /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
  403. firefox DOMMouseScroll detail 下3 上-3
  404. firefox wheel detlaY 下3 上-3
  405. IE9-11 wheel deltaY 下40 上-40
  406. chrome wheel deltaY 下100 上-100 */
  407. /* istanbul ignore next */
  408. const fixWheelType = "onmousewheel" in document$1 ? "mousewheel" : document$1.onwheel !== void 666 ? "wheel" : "DOMMouseScroll";
  409. const fixWheelDelta = fixWheelType === "mousewheel" ? "wheelDetla" : fixWheelType === "wheel" ? "deltaY" : "detail";
  410. eventHooks.wheel = function (dom) {
  411. addDocumentEvent(dom, fixWheelType, function (e) {
  412. var delta = e[fixWheelDelta] > 0 ? -120 : 120;
  413. var deltaY = ~~dom.__wheel + delta;
  414. dom.__wheel = deltaY;
  415. e = new SyntheticEvent(e);
  416. e.type = "wheel";
  417. e.deltaY = deltaY;
  418. dispatchEvent(e);
  419. });
  420. };
  421. var fixFocus = {};
  422. "blur,focus".replace(/\w+/g, function (type) {
  423. eventHooks[type] = function () {
  424. if (!fixFocus[type]) {
  425. fixFocus[type] = true;
  426. addDocumentEvent(document$1, type, dispatchEvent, true);
  427. }
  428. };
  429. });
  430. /**
  431. *
  432. DOM通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;
  433. 对于其他事件,这个属性的值是null。IE不支持realtedTarget属性,但提供了保存着同样信息的不同属性。
  434. 在mouseover事件触发时,IE的fromElement属性中保存了相关元素;
  435. 在mouseout事件出发时,IE的toElement属性中保存着相关元素。
  436. 但fromElement与toElement可能同时都有值
  437. */
  438. function getRelatedTarget(e) {
  439. if (!e.timeStamp) {
  440. e.relatedTarget = e.type === "mouseover" ? e.fromElement : e.toElement;
  441. }
  442. return e.relatedTarget;
  443. }
  444. function contains(a, b) {
  445. if (b) {
  446. while ((b = b.parentNode)) {
  447. if (b === a) {
  448. return true;
  449. }
  450. }
  451. }
  452. return false;
  453. }
  454. String("mouseenter,mouseleave").replace(/\w+/g, function (type) {
  455. eventHooks[type] = function (dom, name) {
  456. var mark = "__" + name;
  457. if (!dom[mark]) {
  458. dom[mark] = true;
  459. var mask = name === "mouseenter" ? "mouseover" : "mouseout";
  460. addDocumentEvent(dom, mask, function (e) {
  461. let t = getRelatedTarget(e);
  462. if (!t || (t !== dom && !contains(dom, t))) {
  463. var common = getLowestCommonAncestor(dom, t);
  464. //由于不冒泡,因此paths长度为1
  465. dispatchEvent(e, name, common);
  466. }
  467. });
  468. }
  469. };
  470. });
  471. function getLowestCommonAncestor(instA, instB) {
  472. var depthA = 0;
  473. for (var tempA = instA; tempA; tempA = tempA.parentNode) {
  474. depthA++;
  475. }
  476. var depthB = 0;
  477. for (var tempB = instB; tempB; tempB = tempB.parentNode) {
  478. depthB++;
  479. }
  480. // If A is deeper, crawl up.
  481. while (depthA - depthB > 0) {
  482. instA = instA.parentNode;
  483. depthA--;
  484. }
  485. // If B is deeper, crawl up.
  486. while (depthB - depthA > 0) {
  487. instB = instB.parentNode;
  488. depthB--;
  489. }
  490. // Walk in lockstep until we find a match.
  491. var depth = depthA;
  492. while (depth--) {
  493. if (instA === instB) {
  494. return instA;
  495. }
  496. instA = instA.parentNode;
  497. instB = instB.parentNode;
  498. }
  499. return null;
  500. }
  501. //之前是 mount的时候setDomAttr一个方法 diff的时候diffProps一个方法
  502. //后来发现 写着写着要修改点setDomAttr的内容 diff的时候还要在判断一遍
  503. //那干脆把这两个合成一个方法好了
  504. function diffProps(prev, now) {
  505. var props = now.props;
  506. var hostNode = now.mayInfo.hostNode;
  507. var prevStyle = prev && prev.props.style;
  508. var nowStyle = props.style;
  509. if (!prev) { //setDomAttr
  510. for (var key in props) {
  511. setDomAttr(hostNode, key, props[key]);
  512. }
  513. if (nowStyle) {
  514. patchStyle(hostNode, prevStyle, nowStyle);
  515. }
  516. } else {
  517. var prevProps = prev.props;
  518. for (var name in props) {
  519. if (name !== 'children' && !(props[name] === prevProps[name])) {
  520. setDomAttr(hostNode, name, props[name]);
  521. }
  522. }
  523. for (var prop in prevProps) {
  524. if (prop !== 'children' && (props[prop] === void 666)) {
  525. removeDomAttr(hostNode, prevProps, prop);
  526. }
  527. }
  528. if (prevStyle !== nowStyle) {
  529. patchStyle(hostNode, prevStyle, nowStyle);
  530. }
  531. }
  532. }
  533. var FormElement = {
  534. input: 1,
  535. select: 1,
  536. // option: 1,
  537. textarea: 1
  538. };
  539. /**
  540. * 设置DOM属性
  541. * @param {*} dom
  542. * @param {*} key
  543. * @param {*} val
  544. */
  545. function setDomAttr(dom, key, val) {
  546. var nodeType = dom.nodeType;
  547. // Don't get/set attributes on text, comment and attribute nodes
  548. if (nodeType === 3 || nodeType === 8 || nodeType === 2) {
  549. return;
  550. }
  551. if (!isEvent(key)) {
  552. switch (key) {
  553. case 'children':
  554. case 'style':
  555. case 'key':
  556. break;
  557. case 'dangerouslySetInnerHTML':
  558. var html = val && val.__html;
  559. dom.innerHTML = html;
  560. break;
  561. case 'defaultValue': //input等受控组件
  562. key = 'value';
  563. case 'className':
  564. key = 'class';
  565. default:
  566. if (key in dom) { //property
  567. try {
  568. if (val !== null && val !== false) {
  569. dom[key] = val;
  570. }
  571. } catch (e) {
  572. dom.setAttribute(key, val + '');
  573. }
  574. } else { //attribute
  575. if (val !== null && val !== false) {
  576. //attribute 永远是字符串
  577. dom.setAttribute(key, val + '');
  578. } else {
  579. //如果是null 或 false 不必添加
  580. dom.removeAttribute(key);
  581. }
  582. }
  583. break;
  584. }
  585. } else {
  586. var e = key.substring(2).toLowerCase();
  587. var eventName = getBrowserName(key);
  588. var listener = dom._listener || (dom._listener = {});
  589. if (!listener[e]) {
  590. //添加过一次之后不必再添加;
  591. addEvent(eventName);
  592. var hook = eventHooks[eventName];
  593. if (hook) {
  594. //input的change等特殊事件需要特殊处理
  595. hook(dom, eventName);
  596. }
  597. }
  598. listener[e] = val;
  599. }
  600. }
  601. function removeDomAttr(dom, props, key) {
  602. var nodeType = dom.nodeType;
  603. // Don't get/set attributes on text, comment and attribute nodes
  604. if (nodeType === 3 || nodeType === 8 || nodeType === 2) {
  605. return;
  606. }
  607. if (!isEvent(key)) {
  608. switch (key) {
  609. case 'dangerouslySetInnerHTML':
  610. dom.innerHTML = '';
  611. case 'className':
  612. dom.removeAttribute('class');
  613. break;
  614. default:
  615. if (key in dom) {
  616. dom[key] = '';
  617. } else {
  618. dom.removeAttribute(key);
  619. }
  620. }
  621. } else {
  622. var e = key.substring(2).toLowerCase();
  623. if (dom._listener && dom._listener[e]) {
  624. delete dom._listener[e];
  625. }
  626. }
  627. }
  628. function isEvent(name) {
  629. return /^on[A-Z]/.test(name);
  630. }
  631. function patchStyle(dom, prevStyle, newStyle) {
  632. var _style = '';
  633. for (var name in newStyle) {
  634. var _type = typeof newStyle[name];
  635. //backgroundColor 替换为 background-color Webkit替换为-webkit- ms单独替换一次
  636. var cssName = name.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^ms-/i, '-ms-');
  637. switch (_type) {
  638. case 'string':
  639. _style = newStyle[name].trim();
  640. break;
  641. case 'number':
  642. _style = newStyle[name];
  643. if (cssSuffix[name]) {
  644. _style += newStyle[name] !== 0 ? +cssSuffix[name] : '';
  645. }
  646. break;
  647. case 'boolean':
  648. _style = '';
  649. break;
  650. default:
  651. _style = newStyle[name];
  652. break;
  653. }
  654. dom.style[cssName] = _style;
  655. }
  656. for (var key in prevStyle) {
  657. if (!newStyle || !(key in newStyle)) {
  658. key = key.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^ms-/i, '-ms-');
  659. dom.style[key] = '';
  660. }
  661. }
  662. }
  663. /**
  664. input, select, textarea这几个元素如果指定了value/checked的**状态属性**,就会包装成受控组件或非受控组件
  665. 受控组件是指,用户除了为它指定**状态属性**,还为它指定了onChange/onInput/disabled等用于控制此状态属性
  666. 变动的属性
  667. 反之,它就是非受控组件,非受控组件会在框架内部添加一些事件,阻止**状态属性**被用户的行为改变,只能被setState改变
  668. */
  669. var eGroup = [{
  670. 'onChange': 1,
  671. 'onInput': 1,
  672. 'readOnly': 1,
  673. 'disabled': 1
  674. }, {
  675. 'onChange': 1,
  676. 'onClick': 1,
  677. 'readOnly': 1,
  678. 'disabled': 1
  679. }, {
  680. 'onChange': 1,
  681. 'disabled': 1
  682. }];
  683. function getIsControlled(hostNode, vnode) {
  684. //记录第一次render的值 非受控组件值不可变
  685. var type = hostNode.type;
  686. var hasValue, isControlled, eObj, event, ename;
  687. var vprops = vnode.props;
  688. switch (type) {
  689. case 'text':
  690. case 'textarea':
  691. //非受控组件有value属性 但是没有绑定修改value的onChange等事件
  692. hasValue = 'value' in vprops;
  693. ename = 'oninput';
  694. eObj = eGroup[0];
  695. //如果是非受控组件那么我们需要阻止用户改变数据
  696. event = preventInput;
  697. break;
  698. case 'checkbox':
  699. case 'radio':
  700. hasValue = 'checked' in vprops;
  701. ename = 'onclick';
  702. eObj = eGroup[1];
  703. event = preventClick;
  704. break;
  705. case 'select-one':
  706. case 'select-multiple':
  707. hasValue = 'value' in vprops;
  708. ename = 'onchange';
  709. eObj = eGroup[2];
  710. event = preventChange;
  711. var _val = vnode.props['value'] || vnode.props['defaultValue'] || '';
  712. var _optionsChilds = [].slice.call(hostNode.childNodes);
  713. if (_optionsChilds) {
  714. for (var k = 0; k < _optionsChilds.length; k++) {
  715. var oChild = _optionsChilds[k];
  716. if (oChild.value === _val) {
  717. oChild.selected = true;
  718. hostNode._selectIndex = k;
  719. }
  720. }
  721. }
  722. break;
  723. }
  724. isControlled = hasValue && hasEventProps(vprops, eObj);
  725. if (!isControlled) {
  726. console.warn(vnode.type + (vprops['type'] ? ('[type=' + vprops['type'] + ']') : '') + '元素为非受控组件,用户无法通过输入改变元素的值;更多信息参见React官方文档https://reactjs.org/docs/uncontrolled-components.html');
  727. setDomAttr(hostNode, ename, event);
  728. }
  729. return isControlled;
  730. }
  731. function preventInput(e) {
  732. var target = e.target;
  733. var name = e.type === "textarea" ? "innerHTML" : "value";
  734. target[name] = target._lastValue;
  735. }
  736. function preventClick(e) {
  737. e.preventDefault();
  738. }
  739. function preventChange(e) {
  740. var target = e.target;
  741. if (target._selectIndex) {
  742. target.options[target._selectIndex].selected = true;
  743. }
  744. }
  745. function hasEventProps(props, events) {
  746. for (var key in props) {
  747. if (events[key]) {
  748. return true;
  749. }
  750. }
  751. }
  752. const cssSuffix = {
  753. //需要加后缀如 px s(秒)等css属性摘出来
  754. //其实用正则更简洁一些,不过可能 可读性可维护性不如key value
  755. //动画属性(Animation)
  756. animationDelay: 's',
  757. //CSS 边框属性(Border 和 Outline)
  758. borderBottomWidth: 'px',
  759. borderLeftWidth: 'px',
  760. borderRightWidth: 'px',
  761. borderTopWidth: 'px',
  762. borderWidth: 'px',
  763. outlineWidth: 'px',
  764. borderBottomLeftRadius: 'px',
  765. borderBottomRightRadius: 'px',
  766. borderRadius: 'px',
  767. borderTopLeftRadius: 'px',
  768. borderTopRightRadius: 'px',
  769. //Box 属性
  770. rotation: 'deg',
  771. //CSS 尺寸属性(Dimension)
  772. height: 'px',
  773. maxHeight: 'px',
  774. maxWidth: 'px',
  775. minHeight: 'px',
  776. minWidth: 'px',
  777. width: 'px',
  778. //CSS 字体属性(Font) font-variant:small-caps; 段落设置为小型大写字母字体
  779. fontSize: 'px',
  780. //CSS 外边距属性(Margin)
  781. margin: 'px',
  782. marginLeft: 'px',
  783. marginRight: 'px',
  784. marginTop: 'px',
  785. marginBottom: 'px',
  786. //多列属性(Multi-column)
  787. columnGap: 'px',
  788. WebkitColumnGap: 'px',
  789. MozColumnGap: 'px',
  790. columnRuleWidth: 'px',
  791. WebkitColumnRuleWidth: 'px',
  792. MozColumnRuleWidth: 'px',
  793. columnWidth: 'px',
  794. WebkitColumnWidth: 'px',
  795. MozColumnWidth: 'px',
  796. //CSS 内边距属性(Padding)
  797. padding: 'px',
  798. paddingLeft: 'px',
  799. paddingRight: 'px',
  800. paddingTop: 'px',
  801. paddingBottom: 'px',
  802. //CSS 定位属性(Positioning)
  803. left: 'px',
  804. right: 'px',
  805. top: 'px',
  806. bottom: 'px',
  807. //CSS 文本属性(Text)
  808. letterSpacing: 'px',
  809. lineHeight: 'px'
  810. };
  811. var NAMESPACE = {
  812. html: 'http://www.w3.org/1999/xhtml',
  813. mathml: 'http://www.w3.org/1998/Math/MathML',
  814. svg: 'http://www.w3.org/2000/svg'
  815. };
  816. /**
  817. * 如果instance具备getChildContext方法 则调用
  818. * @param {component实例} instance
  819. * @param {当前上下文} context
  820. */
  821. function getChildContext(instance, context) {
  822. var prevProps = instance.props;
  823. if (instance.nextProps) {
  824. instance.props = instance.nextProps;
  825. }
  826. var getContext = instance.getChildContext();
  827. if (instance.nextProps) {
  828. instance.props = prevProps;
  829. }
  830. if (getContext && typeof getContext === 'object') {
  831. if (!context) {
  832. context = {};
  833. }
  834. context = Object.assign(context, getContext);
  835. }
  836. return context;
  837. }
  838. function getContextByTypes(context, typeCheck) {
  839. var ret = {};
  840. if (!context || !typeCheck) {
  841. return ret;
  842. }
  843. for (const key in typeCheck) {
  844. if (context.hasOwnProperty(key)) {
  845. ret[key] = context[key];
  846. }
  847. }
  848. return ret;
  849. }
  850. var REAL_SYMBOL = typeof Symbol === "function" && Symbol.iterator;
  851. var FAKE_SYMBOL = "@@iterator";
  852. function getIteractor(a) {
  853. var iteratorFn = REAL_SYMBOL && a[REAL_SYMBOL] || a[FAKE_SYMBOL];
  854. if (iteratorFn && iteratorFn.call) {
  855. return iteratorFn;
  856. }
  857. }
  858. function callIteractor$1(iteratorFn, children) {
  859. var iterator = iteratorFn.call(children),
  860. step,
  861. ret = [];
  862. if (iteratorFn !== children.entries) {
  863. while (!(step = iterator.next()).done) {
  864. ret.push(step.value);
  865. }
  866. } else {
  867. //Map, Set
  868. while (!(step = iterator.next()).done) {
  869. var entry = step.value;
  870. if (entry) {
  871. ret.push(entry[1]);
  872. }
  873. }
  874. }
  875. return ret;
  876. }
  877. //https://segmentfault.com/a/1190000010336457 司徒正美先生写的分析
  878. //hydrate是最早出现于inferno(另一个著名的react-like框架),并相邻的简单数据类型合并成一个字符串。
  879. //因为在react的虚拟DOM体系中,字符串相当于一个文本节点。减少children中的个数,
  880. //就相当减少实际生成的文本节点的数量,也减少了以后diff的数量,能有效提高性能。
  881. //render过程中有Key的 是最有可能变动的,无Key的很可能不会变(绝大部分情况)
  882. //把children带Key的放一起 不带Key的放一起(因为他们很可能不变化,顺序也不变减少diff寻找)
  883. function transformChildren(renderedVnode, parent) {
  884. var children = renderedVnode.props.children || null;
  885. if (children && !Array.isArray(children)) {
  886. children = [children];
  887. }
  888. var len = children ? children.length : 0;
  889. var childList = [].slice.call(parent.childNodes);
  890. var result = children ? {} : null;
  891. //如有undefined null 简单数据类型合并 noCount++;
  892. var noCount = 0;
  893. for (var i = 0; i < len; i++) {
  894. var c = children[i];
  895. var __type = typeof c;
  896. switch (__type) {
  897. case 'object':
  898. if (c.type) {
  899. if (c.mayInfo.reused) {
  900. //如果该组件 diff 两次 第一次vnode重用之后_reused为true
  901. //生成vchildren时需要其为false 否则第二次diff
  902. c.mayInfo.reused = false;
  903. }
  904. var _key = genKey(c);
  905. if (!result[_key]) {
  906. result[_key] = [c];
  907. } else {
  908. result[_key].push(c);
  909. }
  910. if (c.ref) { //如果子dom有ref 标识一下
  911. var owner = renderedVnode.mayInfo.refOwner;
  912. if (owner) {
  913. if (owner.refs) {
  914. owner.refs[c.ref] = c.mayInfo.instance || c.mayInfo.hostNode || null;
  915. } else {
  916. owner.refs = {};
  917. owner.refs[c.ref] = c.mayInfo.instance || c.mayInfo.hostNode || null;
  918. }
  919. }
  920. }
  921. } else {
  922. var iteratorFn = getIteractor(c);
  923. if (iteratorFn) {
  924. var ret = callIteractor$1(iteratorFn, c);
  925. for (var _i = 0; _i < ret.length; _i++) {
  926. var _key = genKey(ret[_i]);
  927. if (!result[_key]) {
  928. result[_key] = [ret[_i]];
  929. } else {
  930. result[_key].push(ret[_i]);
  931. }
  932. }
  933. }
  934. }
  935. break;
  936. case 'number':
  937. case 'string':
  938. //相邻的简单数据类型合并成一个字符串
  939. var tran = {
  940. type: '#text',
  941. mtype: 4,
  942. value: c,
  943. mayInfo: {}
  944. };
  945. if (childList[i - noCount]) {
  946. tran.mayInfo.hostNode = childList[i - noCount];
  947. }
  948. if ((i + 1 < len)) {
  949. var _ntype = typeof children[i + 1 - noCount];
  950. if (_ntype === 'string' || _ntype === 'number') {
  951. tran.value += children[i + 1 - noCount];
  952. noCount++;
  953. i++;
  954. }
  955. }
  956. var _k = '#text';
  957. if (!result[_k]) {
  958. result[_k] = [tran];
  959. } else {
  960. result[_k].push(tran);
  961. }
  962. break;
  963. default:
  964. noCount++;
  965. break;
  966. }
  967. }
  968. return result;
  969. }
  970. function genKey(child) {
  971. return !child.key ? (child.type.name || child.type) : ('_$' + child.key);
  972. }
  973. var mountOrder = 0;
  974. function buildComponentFromVnode(vnode) {
  975. var props = vnode.props;
  976. var key = vnode.key;
  977. var ref = vnode.ref;
  978. var context = vnode.context;
  979. var inst, rendered;
  980. var Ctor = vnode.type;
  981. //Component PureComponent
  982. if (Ctor.prototype && Ctor.prototype.render) {
  983. //props, context需要放在前俩
  984. inst = new Ctor(props, context, key, ref);
  985. //constructor里面props不可变
  986. inst.props = props;
  987. inst.refType = vnode.refType;
  988. inst.mayInst.mountOrder = mountOrder;
  989. mountOrder++;
  990. //_lifeState来控制生命周期中调用setState的作用
  991. //为0代表刚创建完component实例 (diff之后也会重置为0)
  992. inst.mayInst.lifeState = 0;
  993. if (inst.componentWillMount) {
  994. //此时如果在componentWillMount调用setState合并state即可
  995. //为1代表componentWillMount
  996. inst.mayInst.lifeState = 1;
  997. inst.componentWillMount();
  998. }
  999. if (inst.mayInst.mergeStateQueue) {
  1000. inst.state = mergeState(inst);
  1001. }
  1002. //为2代表开始render
  1003. //children 初次render的生命周期render DidMount
  1004. //调用父组件的setState 都放在父组件的下一周期;
  1005. inst.mayInst.lifeState = 2;
  1006. rendered = inst.render(props, context);
  1007. if (inst.getChildContext) {
  1008. context = getChildContext(inst, context);
  1009. }
  1010. if (vnode.getContext) {
  1011. inst.context = getContextByTypes(context, Ctor.contextTypes);
  1012. }
  1013. rendered && (rendered.mayInfo.refOwner = inst);
  1014. } else {
  1015. //StatelessComponent 我们赋给它一个inst 省去之后判断inst是否为空等;
  1016. inst = {
  1017. mayInst: {
  1018. stateless: true
  1019. },
  1020. render: function (type) {
  1021. return type(this.props, this.context);
  1022. }
  1023. };
  1024. rendered = inst.render.call(vnode, Ctor);
  1025. //should support module pattern components
  1026. if (rendered && rendered.render) {
  1027. console.warn('不推荐使用这种module-pattern component建议换成正常的Component形式,目前只支持render暂不支持其它生命周期方法');
  1028. rendered = rendered.render.call(vnode, props, context);
  1029. }
  1030. }
  1031. if (rendered) {
  1032. //需要向下传递context
  1033. rendered.context = context;
  1034. }
  1035. vnode.mayInfo.instance = inst;
  1036. inst.mayInst.rendered = rendered;
  1037. return rendered;
  1038. }
  1039. //React是根据type类型分成不同的Component各自具备各自的mount与update方法
  1040. //我们这里简化成根据type类型调用不同的方法
  1041. //mountDOM vnode.type为string直接createElement 然后render children即可
  1042. //mountComposite vnode.type为function 需实例化component 再render children
  1043. var mountStrategy = {
  1044. 1: mountDOM, //dom
  1045. 2: mountComposite, //component
  1046. 3: mountDOM, //svg dom
  1047. 4: mountText //text
  1048. };
  1049. function mountDOM(vnode, isSVG) {
  1050. var vtype = vnode.type;
  1051. vnode.mayInfo.isSVG = isSVG;
  1052. var hostNode = !isSVG ? document.createElement(vtype) : document.createElementNS(NAMESPACE.svg, vnode.type);
  1053. if (Refs.isRoot) {
  1054. Refs.currentOwner = hostNode;
  1055. hostNode.refs = {};
  1056. Refs.isRoot = false;
  1057. }
  1058. vnode.mayInfo.hostNode = hostNode;
  1059. diffProps(null, vnode);
  1060. var children = vnode.props.children;
  1061. if (!Array.isArray(children)) {
  1062. children = [children];
  1063. }
  1064. var cdom, c;
  1065. var len = children.length;
  1066. for (let i = 0; i < len; i++) {
  1067. var c = children[i];
  1068. var type = typeof c;
  1069. switch (type) {
  1070. case 'number':
  1071. case 'string':
  1072. cdom = document.createTextNode(c);
  1073. if ((i + 1) < len && (typeof children[i + 1] === 'string')) {
  1074. cdom.nodeValue += children[i + 1];
  1075. i++;
  1076. }
  1077. hostNode.appendChild(cdom);
  1078. break;
  1079. case 'object': //vnode
  1080. if (c.type) {
  1081. c.context = getContextByTypes(vnode.context, c.type.contextTypes);
  1082. cdom = mountStrategy[c.mtype](c, isSVG);
  1083. c.mtype === 2 && (c.mayInfo.instance.mayInst.hostNode = cdom);
  1084. hostNode.appendChild(cdom);
  1085. } else { //有可能是子数组iterator
  1086. var iteratorFn = getIteractor(c);
  1087. if (iteratorFn) {
  1088. var ret = callIteractor$1(iteratorFn, c);
  1089. for (var _i = 0; _i < ret.length; _i++) {
  1090. cdom = mountStrategy[ret[_i].mtype](ret[_i], isSVG);
  1091. ret[_i].mayInfo.hostNode = cdom;
  1092. hostNode.appendChild(cdom);
  1093. }
  1094. }
  1095. }
  1096. }
  1097. }
  1098. vnode.mayInfo.vChildren = transformChildren(vnode, hostNode);
  1099. if (FormElement[vtype]) {
  1100. //如果是受控组件input select之类需要特殊处理下
  1101. if (vnode.props) {
  1102. var _val = vnode.props['value'] || vnode.props['defaultValue'] || '';
  1103. getIsControlled(hostNode, vnode);
  1104. hostNode._lastValue = _val;
  1105. }
  1106. }
  1107. //本来想放在调度模块的 但是这种vnode type为dom类型的 func是要在DidMount之前调用的
  1108. //因为DidMount中可能用到;
  1109. if (vnode.ref) {
  1110. Refs.attachRef(vnode, hostNode);
  1111. }
  1112. return hostNode;
  1113. }
  1114. function mountComposite(vnode, isSVG) {
  1115. var hostNode = null;
  1116. var rendered = buildComponentFromVnode(vnode);
  1117. var inst = vnode.mayInfo.instance;
  1118. if (!inst.mayInst.stateless && Refs.isRoot) {
  1119. Refs.currentOwner = inst;
  1120. inst.refs = {};
  1121. Refs.isRoot = false;
  1122. }
  1123. if (rendered) {
  1124. if (!isSVG) {
  1125. //svg的子节点namespace也是svg
  1126. isSVG = rendered.mtype === 3;
  1127. }
  1128. //递归遍历 深度优先
  1129. hostNode = mountStrategy[rendered.mtype](rendered, isSVG);
  1130. //dom diff需要分类一下children以方便diff
  1131. rendered.mayInfo.vChildren = transformChildren(rendered, hostNode);
  1132. // rendered.mayInfo.hostNode = hostNode;
  1133. } else { //render 返回null
  1134. hostNode = document.createComment('empty');
  1135. vnode.mayInfo.hostNode = hostNode;
  1136. //用于isMounted 判断 即使是null
  1137. inst.mayInst.isEmpty = true;
  1138. }
  1139. if (inst.componentDidMount) {
  1140. lifeCycleQueue.push(inst.componentDidMount.bind(inst));
  1141. } else {
  1142. //如果没有回调则其render生命周期结束lifeState为0
  1143. inst.mayInst.lifeState = 0;
  1144. }
  1145. if (vnode.ref) {
  1146. Refs.attachRef(vnode, inst);
  1147. }
  1148. return hostNode;
  1149. }
  1150. function mountText(vnode) {
  1151. if (vnode) {
  1152. var node = recyclables['#text'].pop();
  1153. if (node) {
  1154. node.nodeValue = node.value;
  1155. return node;
  1156. }
  1157. return document.createTextNode(vnode.value);
  1158. } else {
  1159. return document.createComment('empty');
  1160. }
  1161. }
  1162. function disposeVnode(vnode) {
  1163. if (!vnode) {
  1164. return;
  1165. }
  1166. if (vnode.refType === 1) {
  1167. vnode.ref(null);
  1168. vnode.ref = null;
  1169. }
  1170. if (vnode.mayInfo.instance) {
  1171. disposeComponent(vnode, vnode.mayInfo.instance);
  1172. } else if (vnode.mtype === 1) {
  1173. disposeDomVnode(vnode);
  1174. }
  1175. vnode.mayInfo = null;
  1176. }
  1177. function disposeDomVnode(vnode) {
  1178. var children = vnode.mayInfo.vChildren;
  1179. if (children) {
  1180. for (var c in children) {
  1181. children[c].forEach(function (child) {
  1182. disposeVnode(child);
  1183. });
  1184. }
  1185. vnode.mayInfo.vChildren = null;
  1186. }
  1187. if (vnode.mayInfo.refOwner) {
  1188. vnode.mayInfo.refOwner = null;
  1189. }
  1190. vnode.mayInfo = null;
  1191. }
  1192. function disposeComponent(vnode, instance) {
  1193. if (instance.setState) {
  1194. instance.setState = noop$1;
  1195. instance.forceUpdate = noop$1;
  1196. }
  1197. if (instance.componentWillUnmount) {
  1198. instance.componentWillUnmount();
  1199. instance.componentWillUnmount = noop$1;
  1200. }
  1201. if (instance.refs) {
  1202. instance.refs = null;
  1203. }
  1204. if (instance.mayInst.rendered) {
  1205. // vnode.mayInfo.rendered = null;
  1206. disposeVnode(instance.mayInst.rendered);
  1207. }
  1208. instance.mayInst.forceUpdate = instance.mayInst.dirty = vnode.mayInfo.instance = instance.mayInst = null;
  1209. }
  1210. var isStandard = 'textContent' in document;
  1211. var fragment = document.createDocumentFragment();
  1212. function disposeDom(dom) {
  1213. if (dom._listener) {
  1214. dom._listener = null;
  1215. }
  1216. if (dom.nodeType === 1) {
  1217. if (isStandard) {
  1218. dom.textContent = '';
  1219. } else {
  1220. emptyElement(dom);
  1221. }
  1222. } else if (dom.nodeType === 3) {
  1223. if (recyclables['#text'].length < 100) {
  1224. recyclables['#text'].push(dom);
  1225. }
  1226. }
  1227. fragment.appendChild(dom);
  1228. fragment.removeChild(dom);
  1229. }
  1230. function emptyElement(dom) {
  1231. var c;
  1232. while (c = dom.firstChild) {
  1233. emptyElement(c);
  1234. dom.removeChild(c);
  1235. }
  1236. }
  1237. function noop$1() { }
  1238. //diff根据vnode的不同类型调用不同的diff方法~
  1239. //其实写着写着就发现还是类似React 根据不同的类型生成不同的Component
  1240. //拥有对应的diff方法;
  1241. var updateStrategy = {
  1242. 1: updateDOM, //dom
  1243. 2: updateComposite, //component
  1244. 3: updateDOM, //svg dom
  1245. 4: updateText //text
  1246. };
  1247. function updateDOM(prevVnode, newVnode) {
  1248. if (prevVnode.refType === 1) {
  1249. prevVnode.ref(null);
  1250. }
  1251. var hostNode = (prevVnode && prevVnode.mayInfo.hostNode) || null;
  1252. var vtype = newVnode.type;
  1253. if (!newVnode.mayInfo.hostNode) {
  1254. newVnode.mayInfo.hostNode = hostNode;
  1255. }
  1256. if (Refs.isRoot) {
  1257. Refs.currentOwner = hostNode;
  1258. hostNode.refs = {};
  1259. Refs.isRoot = false;
  1260. }
  1261. var isSVG = hostNode && hostNode.namespaceURI === NAMESPACE.svg;
  1262. if (isSVG) {
  1263. newVnode.mayInfo.isSVG = true;
  1264. }
  1265. diffProps(prevVnode, newVnode);
  1266. diffChildren(prevVnode, newVnode, hostNode);
  1267. newVnode.mayInfo.vChildren = transformChildren(newVnode, hostNode);
  1268. if (FormElement[vtype]) {
  1269. //如果是受控组件input select之类需要特殊处理下
  1270. if (newVnode.props) {
  1271. var isControlled = getIsControlled(hostNode, newVnode);
  1272. var _val, hasSelected;
  1273. if (isControlled) {
  1274. _val = newVnode.props['value'] || hostNode._lastValue || '';
  1275. switch (vtype) {
  1276. case 'select':
  1277. var _optionsChilds = [].slice.call(hostNode.childNodes);
  1278. if (_optionsChilds) {
  1279. for (var k = 0; k < _optionsChilds.length; k++) {
  1280. var oChild = _optionsChilds[k];
  1281. if (oChild.value === _val) {
  1282. oChild.selected = true;
  1283. hasSelected = true;
  1284. } else {
  1285. oChild.selected = false;
  1286. }
  1287. }
  1288. if (!hasSelected) { //如果给定value没有选中的 默认第一个
  1289. hostNode.value = _optionsChilds[0].value;
  1290. }
  1291. }
  1292. break;
  1293. }
  1294. } else {
  1295. //如果reRender时 dom去掉了value属性 则其变为非受控组件 value取上一次的值
  1296. hostNode.value = hostNode._lastValue || '';
  1297. }
  1298. }
  1299. }
  1300. if (newVnode.ref) {
  1301. Refs.attachRef(newVnode, hostNode);
  1302. }
  1303. return hostNode;
  1304. }
  1305. function updateComposite(prevVnode, newVnode) {
  1306. if (prevVnode.refType === 1) {
  1307. prevVnode.ref(null);
  1308. }
  1309. //如果newVnode没有定义contextTypes 在componentWillReceiveProps等生命周期方法中
  1310. //是不应该传入context的 那么用空的temporaryContext代替
  1311. var temporaryContext = {};
  1312. var context = newVnode.context || {};
  1313. if (newVnode.getContext) {
  1314. context = getContextByTypes(context, newVnode.type.contextTypes);
  1315. temporaryContext = context;
  1316. }
  1317. var instance = prevVnode.mayInfo.instance;
  1318. var prevRendered = instance.mayInst.rendered;
  1319. var hostNode = (prevRendered && prevRendered.mtype === 1) ? prevRendered.mayInfo.hostNode : instance.mayInst.hostNode;
  1320. //empty代表prevVnode为null
  1321. var isEmpty = instance.mayInst.isEmpty || (hostNode && hostNode.nodeType === 8);
  1322. var newDom, newRendered, prevState, prevProps;
  1323. var skip = false;
  1324. if (!instance.mayInst.stateless) {
  1325. //需要兼容componentWillReceiveProps直接this.state={///}的情况
  1326. //先保存下之前的state
  1327. prevState = instance.state;
  1328. prevProps = prevVnode.props;
  1329. //lifeState为3组件开始diff
  1330. //WillReceive WillUpdate render DidUpdate等周期setState放到下一周期;
  1331. instance.mayInst.lifeState = 3;
  1332. //用于mergeState如果setState传入一个function s.call(instance, newState, instance.nextProps || instance.props);
  1333. //其参数应当是newState nextProps
  1334. instance.nextProps = newVnode.props;
  1335. if (instance.getChildContext) {
  1336. //getChildContext 有可能用到新的props
  1337. context = getChildContext(instance, context);
  1338. }
  1339. var newState = mergeState(instance);
  1340. //如果context与props都没有改变,那么就不会触发组件的receive,render,update等一系列钩子
  1341. //但还会继续向下比较
  1342. var needReceive = prevVnode !== newVnode || prevVnode.context !== context;
  1343. if (needReceive) {
  1344. if (instance.componentWillReceiveProps) {
  1345. //componentWillReceiveProps中调用了setState 合并state
  1346. instance.mayInst.lifeState = 1;
  1347. instance.componentWillReceiveProps(newVnode.props, temporaryContext);
  1348. if (instance.mayInst.mergeStateQueue && instance.mayInst.mergeStateQueue.length > 0) {
  1349. newState = mergeState(instance);
  1350. } else { //this.state={///}的情况
  1351. if (instance.state !== prevState) {
  1352. newState = instance.state;
  1353. instance.state = prevState;
  1354. }
  1355. }
  1356. }
  1357. instance.mayInst.lifeState = 3;
  1358. } else {
  1359. var rendered = instance.mayInst.rendered;
  1360. //context穿透更新问题
  1361. rendered.context = newVnode.temporaryContext || context;
  1362. hostNode = updateStrategy[rendered.mtype](rendered, rendered);
  1363. return hostNode;
  1364. }
  1365. //shouldComponentUpdate 返回false 则不进行子组件渲染
  1366. if (!instance.mayInst.forceUpdate && instance.shouldComponentUpdate && instance.shouldComponentUpdate(newVnode.props, newState, temporaryContext) === false) {
  1367. skip = true;
  1368. } else if (instance.componentWillUpdate) {
  1369. instance.componentWillUpdate(newVnode.props, newState, temporaryContext);
  1370. }
  1371. newVnode.mayInfo.instance = instance;
  1372. instance.props = newVnode.props;
  1373. if (skip) {
  1374. instance.state = newState;
  1375. instance.context = context;
  1376. instance.mayInst.dirty = false;
  1377. return hostNode;
  1378. }
  1379. instance.state = newState;
  1380. instance.context = context;
  1381. if (Refs.isRoot) {
  1382. Refs.currentOwner = instance;
  1383. Refs.currentOwner.refs = {};
  1384. Refs.isRoot = false;
  1385. }
  1386. newRendered = instance.render();
  1387. newRendered && (newRendered.context = context);
  1388. instance.mayInst.rendered = newRendered;
  1389. if (!isEmpty && newRendered) {
  1390. if (isSameType(prevRendered, newRendered)) {
  1391. hostNode = updateStrategy[newRendered.mtype](prevRendered, newRendered);
  1392. newRendered.mayInfo.hostNode = hostNode;
  1393. } else {
  1394. disposeVnode(prevRendered);
  1395. var isSVG = newRendered.mtype === 3;
  1396. newDom = mountStrategy[newRendered.mtype](newRendered, isSVG);
  1397. newRendered.mayInfo.hostNode = newDom;
  1398. hostNode.parentNode.replaceChild(newDom, hostNode);
  1399. }
  1400. } else {
  1401. if (isEmpty && newRendered) {
  1402. var isSVG = newRendered.mtype === 3;
  1403. newDom = mountStrategy[newRendered.mtype](newRendered, isSVG);
  1404. newRendered.mayInfo.hostNode = newDom;
  1405. if (hostNode.parentNode) {
  1406. hostNode.parentNode.replaceChild(newDom, hostNode);
  1407. }
  1408. } else {
  1409. hostNode = document.createComment('empty');
  1410. instance.mayInst.hostNode = hostNode;
  1411. instance.mayInst.isEmpty = true;
  1412. }
  1413. //如果之前node为空 或 新render的为空 直接释放之前节点
  1414. disposeVnode(prevRendered);
  1415. }
  1416. if (!instance.mayInst.needNextRender) {
  1417. instance.mayInst.dirty = false;
  1418. instance.mayInst.needNextRender = false;
  1419. }
  1420. if (newDom) {
  1421. hostNode = newDom;
  1422. }
  1423. if (instance.componentDidUpdate) {
  1424. lifeCycleQueue.push(instance.componentDidUpdate.bind(instance, prevProps, prevState, instance.context));
  1425. } else {
  1426. //如果没有回调则其render生命周期结束lifeState为0
  1427. instance.mayInst.lifeState = 0;
  1428. }
  1429. if (newVnode.refType === 1) {
  1430. Refs.attachRef(newVnode, instance);
  1431. }
  1432. } else { //stateless component
  1433. var newRendered = newVnode.type.call(newVnode, newVnode.props, newVnode.context);
  1434. newRendered.context = newVnode.context;
  1435. if (prevRendered && isSameType(prevRendered, newRendered)) {
  1436. hostNode = updateStrategy[newRendered.mtype](prevRendered, newRendered);
  1437. newRendered.mayInfo.hostNode = hostNode;
  1438. } else if (newVnode) {
  1439. disposeVnode(prevRendered);
  1440. var isSVG = newVnode.mtype === 3;
  1441. newDom = mountStrategy[newVnode.mtype](newVnode, isSVG);
  1442. newVnode.mayInfo.hostNode = newDom;
  1443. hostNode.parentNode.replaceChild(newDom, hostNode);
  1444. hostNode = newDom;
  1445. }
  1446. }
  1447. return hostNode;
  1448. }
  1449. function updateText(prev, now) {
  1450. var hostNode = now.mayInfo.hostNode || null;
  1451. if (prev) { //child._prevVnode
  1452. if (hostNode.nodeValue !== now.value) {
  1453. hostNode.nodeValue = now.value;
  1454. }
  1455. } else {
  1456. hostNode = document.createTextNode(now.value);
  1457. }
  1458. return hostNode;
  1459. }
  1460. function diffChildren(prevVnode, updatedVnode, parent) {
  1461. var prevChildren = prevVnode.mayInfo.vChildren || null;
  1462. var newRenderedChild = updatedVnode.props.children;
  1463. if (newRenderedChild && !Array.isArray(newRenderedChild)) {
  1464. newRenderedChild = [newRenderedChild];
  1465. }
  1466. //diff之前 遍历prevchildren 与newChildren 如有相同key的只对其props diff
  1467. var _mountChildren = [];
  1468. var _unMountChildren = [];
  1469. var k, prevK, _prevK, _tran;
  1470. if (newRenderedChild) {
  1471. var len = newRenderedChild.length;
  1472. for (var i = 0; i < len; i++) {
  1473. var c = newRenderedChild[i];
  1474. var t = typeof c;
  1475. switch (t) {
  1476. case 'object':
  1477. k = genKey(c);
  1478. //
  1479. if (c.type && c.type.contextTypes) {
  1480. c.context = getContextByTypes(updatedVnode.context, c.type.contextTypes);
  1481. } else {
  1482. c.context = {};
  1483. //该组件没有定义contextTypes 无法使用context
  1484. //我们还是需要保存一份context
  1485. c.temporaryContext = updatedVnode.context;
  1486. }
  1487. break;
  1488. case 'boolean':
  1489. k = "#text";
  1490. _tran = {
  1491. type: '#text',
  1492. mtype: 4, //text
  1493. value: '',
  1494. mayInfo: {}
  1495. };
  1496. c = _tran;
  1497. break;
  1498. case 'number':
  1499. case 'string':
  1500. k = "#text";
  1501. _tran = {
  1502. type: '#text',
  1503. mtype: 4, //text
  1504. value: c,
  1505. mayInfo: {}
  1506. };
  1507. c = _tran;
  1508. //相邻简单数据类型合并
  1509. if ((i + 1 < newRenderedChild.length)) {
  1510. var _ntype = typeof newRenderedChild[i + 1];
  1511. if (_ntype === 'string' || _ntype === 'number') {
  1512. c.value += newRenderedChild[i + 1];
  1513. i++;
  1514. }
  1515. }
  1516. break;
  1517. case 'undefined':
  1518. break;
  1519. }
  1520. prevK = prevChildren && prevChildren[k];
  1521. if (prevK && prevK.length > 0) { //试试=0 else
  1522. for (var _i = 0; _i < prevK.length; _i++) {
  1523. var vnode = prevK[_i];
  1524. if (c.type === vnode.type && !vnode.mayInfo.used) {
  1525. vnode.mayInfo.hostNode && (c.mayInfo.hostNode = vnode.mayInfo.hostNode);
  1526. c.mayInfo.instance = vnode.mayInfo.instance;
  1527. c.mayInfo.prevVnode = vnode;
  1528. vnode.mayInfo.used = true;
  1529. c.mayInfo.reused = true;
  1530. break;
  1531. }
  1532. }
  1533. }
  1534. if (c) {
  1535. _mountChildren.push(c);
  1536. }
  1537. }
  1538. }
  1539. for (var name in prevChildren) {
  1540. var _c = prevChildren[name];
  1541. for (let j = 0; j < _c.length; j++) {
  1542. if (!_c[j].mayInfo.used) _unMountChildren.push(_c[j]);
  1543. }
  1544. }
  1545. flushMounts(_mountChildren, parent);
  1546. flushUnMounts(_unMountChildren);
  1547. _mountChildren.length = 0;
  1548. }
  1549. function flushMounts(newChildren, parent) {
  1550. for (var _i = 0; _i < newChildren.length; _i++) {
  1551. var child = newChildren[_i];
  1552. var _node = parent.childNodes[_i];
  1553. var newDom;
  1554. if (child.mayInfo.prevVnode) { //如果可以复用之前节点
  1555. var prevChild = child.mayInfo.prevVnode;
  1556. delete child.mayInfo.prevVnode;
  1557. newDom = updateStrategy[child.mtype](prevChild, child);
  1558. if (_node && _node !== newDom) { //移动dom
  1559. newDom = parent.removeChild(newDom);
  1560. parent.insertBefore(newDom, _node);
  1561. } else if (!_node) {
  1562. parent.appendChild(newDom);
  1563. }
  1564. } else { //新增节点
  1565. var isSVG = child.mtype === 3;
  1566. // var isSVG = vnode.namespaceURI === "http://www.w3.org/2000/svg";
  1567. newDom = mountStrategy[child.mtype](child, isSVG);
  1568. child.mtype === 2 && (child.mayInfo.instance.mayInst.hostNode = newDom);
  1569. // child.mayInfo.hostNode = newDom;
  1570. if (_node) {
  1571. parent.insertBefore(newDom, _node);
  1572. } else {
  1573. parent.appendChild(newDom);
  1574. }
  1575. }
  1576. }
  1577. }
  1578. function flushUnMounts(oldChildren) {
  1579. var c, dom;
  1580. while (c = oldChildren.shift()) {
  1581. if (c.mayInfo.hostNode) {
  1582. dom = c.mayInfo.hostNode;
  1583. c.mayInfo.hostNode = null;
  1584. } else if (c.mtype === 2) {
  1585. dom = c.mayInfo.instance.mayInst.hostNode;
  1586. }
  1587. disposeDom(dom);
  1588. disposeVnode(c);
  1589. c = null;
  1590. }
  1591. }
  1592. function isSameType(prev, now) {
  1593. return prev.type === now.type && prev.key === now.key;
  1594. }
  1595. function render(vnode, container, callback) {
  1596. return renderByMay(vnode, container, callback);
  1597. }
  1598. /**
  1599. * render传入的Component都是一个function 该方法的原型对象上绑定了render方法
  1600. * @param {*} vnode
  1601. * @param {*} container
  1602. * @param {*} callback
  1603. */
  1604. var renderByMay = function (vnode, container, callback) {
  1605. var renderedVnode, rootDom, result;
  1606. var lastVnode = container._lastVnode || null;
  1607. if (lastVnode) { //update
  1608. Refs.isRoot = true;
  1609. rootDom = mayUpdate(lastVnode, vnode, container);
  1610. } else {
  1611. if (vnode && vnode.type) {
  1612. //为什么React使用var markup=renderChilden();这样的形式呢; 2018-1-13
  1613. //因为如果按renderComponentChildren(renderedVnode, rootDom, _isSvg);传入container这种
  1614. //碰上component嵌套不好处理 参见 ReactChildReconciler-test的 warns for duplicated array keys with component stack info
  1615. var isSVG = vnode.mtype === 3;
  1616. Refs.isRoot = true;
  1617. rootDom = mountStrategy[vnode.mtype](vnode, isSVG);
  1618. if (rootDom && container && container.appendChild) {
  1619. container.appendChild(rootDom);
  1620. } else {
  1621. throw new Error('container参数错误');
  1622. }
  1623. } else {
  1624. throw new Error('render参数错误');
  1625. }
  1626. }
  1627. var instance = vnode.mayInfo.instance;
  1628. result = instance && !instance.mayInst.stateless && instance || rootDom;
  1629. //执行render过程中的回调函数lifeCycle ref等
  1630. mayQueue.clearQueue();
  1631. if (callback) { //render的 callback
  1632. callback();
  1633. }
  1634. if (instance) {
  1635. //render之后lifeState也初始化为0;
  1636. instance.mayInst.lifeState = 0;
  1637. instance.mayInst.hostNode = rootDom;
  1638. //当我开始着手解决 层层嵌套的component 最底层的那个setState触发的时候lifeState并不为0
  1639. //因为我不能确定其是否有componentDidMount的回调,它在这个回调setState是需要放到下一周期处理的
  1640. //一种办法是该instance如果具备componentDidMount我把其lifeState标个值如10 setState的时候判断
  1641. //另一种办法就是我新建一个instance队列 instance.pendingCallback=componentDidMount
  1642. //然后我每次render完再遍历这个队列有回调就调用 这貌似就是ANU的逻辑吧~
  1643. //快写完了我才发现~惭愧~看来还是自己写写好,不如琢如磨,怎么对这流程了如指掌,不胸有成竹又如何找寻这
  1644. //最优方法
  1645. }
  1646. Refs.isRoot = false;
  1647. Refs.currentOwner = null;
  1648. container._lastVnode = vnode;
  1649. return result;
  1650. };
  1651. function reRender(instance) {
  1652. var prevProps = instance.props;
  1653. var context = instance.context;
  1654. var prevState = instance.state;
  1655. var prevRendered = instance.mayInst.rendered;
  1656. var isEmpty = instance.mayInst.isEmpty;
  1657. var hostNode = instance.mayInst.hostNode;
  1658. var skip = false;
  1659. //lifeState为3组件开始diff
  1660. //WillReceive WillUpdate render DidUpdate等周期setState放到下一周期;
  1661. instance.mayInst.lifeState = 3;
  1662. var newState = mergeState(instance);
  1663. //forceUpdate时 忽略shouldComponentUpdate
  1664. if (!instance.mayInst.forceUpdate && instance.shouldComponentUpdate && instance.shouldComponentUpdate(prevProps, newState, context) === false) {
  1665. skip = true;
  1666. } else if (instance.componentWillUpdate) {
  1667. instance.componentWillUpdate(prevProps, newState, context);
  1668. }
  1669. instance.state = newState;
  1670. //getChildContext有可能setState 所以需要newState再调用
  1671. if (instance.getChildContext) {
  1672. context = getChildContext(instance, context);
  1673. }
  1674. if (skip) {
  1675. instance.mayInst.dirty = false;
  1676. return hostNode;
  1677. }
  1678. if (Refs.isRoot) {
  1679. Refs.currentOwner = instance;
  1680. Refs.isRoot = false;
  1681. }
  1682. var updated = instance.render(prevProps, context);
  1683. instance.mayInst.rendered = updated;
  1684. updated && (updated.context = context);
  1685. if (!updated) {
  1686. disposeVnode(prevRendered);
  1687. return;
  1688. }
  1689. if (!isEmpty && isSameType(prevRendered, updated)) {
  1690. // updated.mayInfo.instance = instance;
  1691. // updated.mayInfo.hostNode = hostNode;
  1692. hostNode = updateStrategy[updated.mtype](prevRendered, updated);
  1693. //mtype === 1在这在设置instance会循环引用
  1694. // updated.mtype === 2 && ();
  1695. updated.mayInfo.vChildren = transformChildren(updated, hostNode);
  1696. instance.mayInst.forceUpdate = null;
  1697. //原先这种diffProps 再diffChildren的方式并未考虑到 render返回之后还是
  1698. //组件怎么办,连续几个组件嵌套children都需要render怎么办 这些情况都是diffProps
  1699. //无法处理的,当时想的是一个组件diff diff之后再diff下一个组件;但如果组件之间发生交互的
  1700. //话是需要在一个处理流程的;那diff我们也需要这种递归的思想了,所以setState的时候我们设置
  1701. //instance的_dirty为true如果父组件 子组件都dirty,父组件向下diff的过程中也会diff子组件
  1702. //此时在子组件diff之后我们要把_dirty设为false 否则因为子组件也在diffQueue之中,会再进行
  1703. //一次diff是多余的;不晓得我说明白没有~参考测试ReactCompositeComponentNestedState-state的
  1704. //should provide up to date values for props
  1705. // diffProps(prevRenderedVnode, updatedVnode);
  1706. } else {
  1707. var isSVG = updated.mtype === 3;
  1708. var dom = mountStrategy[updated.mtype](updated, isSVG);
  1709. //component上的hostNode保持最新
  1710. // var lastVnode = hostNode.parentNode._lastVnode;
  1711. // lastVnode && (lastVnode.mayInfo.hostNode = dom);
  1712. hostNode.parentNode.replaceChild(dom, hostNode);
  1713. // updated.mayInfo.hostNode = dom;
  1714. hostNode = dom;
  1715. instance.mayInst.hostNode = dom;
  1716. updated.mayInfo.vChildren = transformChildren(updated, hostNode);
  1717. instance.mayInst.forceUpdate = null;
  1718. disposeVnode(prevRendered);
  1719. }
  1720. if (instance.componentDidUpdate) {
  1721. instance.componentDidUpdate(prevProps, prevState, instance.context);
  1722. // lifeCycleQueue.push(instance.componentDidUpdate.bind(instance, prevProps, prevState, instance.context));
  1723. } else {
  1724. instance.mayInst.lifeState = 0;
  1725. }
  1726. //needNextRender情况是 子组件在diff生命周期(如WillReceiveProps)调用父组件的setState
  1727. //这种情况下父组件需要再进行一次diff,不过本地diff完成时c.mayInst.dirty 会为false 所以需要
  1728. //mayInst.dirty为true;ReactCompositeComponentState-test 的should update state when called from child cWRP
  1729. if (!instance.mayInst.needNextRender) {
  1730. instance.mayInst.dirty = false;
  1731. instance.mayInst.needNextRender = false;
  1732. }
  1733. }
  1734. function mayUpdate(prevVnode, newVnode, parent) {
  1735. var dom;
  1736. if (isSameType(prevVnode, newVnode)) {
  1737. dom = updateStrategy[newVnode.mtype](prevVnode, newVnode);
  1738. } else {
  1739. var isSVG = newVnode.mtype === 3;
  1740. dom = mountStrategy[newVnode.mtype](newVnode, isSVG);
  1741. var hostNode = (prevVnode && prevVnode.mtype === 1) ? prevVnode.mayInfo.hostNode : prevVnode.mayInfo.instance.mayInst.hostNode;
  1742. if (!parent) {
  1743. parent = hostNode && hostNode.parentNode;
  1744. }
  1745. parent.replaceChild(dom, hostNode);
  1746. disposeVnode(prevVnode);
  1747. hostNode = null;
  1748. }
  1749. // newVnode.mtype === 2 && (newVnode.mayInfo.instance.mayInst.hostNode = dom);
  1750. // newVnode.mayInfo.hostNode = dom;
  1751. return dom;
  1752. }
  1753. function unmountComponentAtNode(dom) {
  1754. var lastVnode = dom._lastVnode;
  1755. if (dom.refs) {
  1756. dom.refs = null;
  1757. }
  1758. if (lastVnode) {
  1759. disposeVnode(lastVnode);
  1760. emptyElement(dom);
  1761. //unmount之后又render
  1762. //参见ReactComponentLifeCycle-test
  1763. //should not reuse an instance when it has been unmounted
  1764. dom._lastVnode.mayInfo = {};
  1765. dom._lastVnode = null;
  1766. }
  1767. }
  1768. function findDOMNode(ref) {
  1769. var ret = null;
  1770. if (ref) {
  1771. if (ref.nodeType === 1) {
  1772. return ref;
  1773. } else {
  1774. var c = ref.mayInst.rendered;
  1775. while (c) {
  1776. if (c.mtype === 1) {
  1777. return c.mayInfo.hostNode;
  1778. } else if (c.mayInfo.hostNode) {
  1779. return c.mayInfo.hostNode;
  1780. }
  1781. c = c.mayInfo.instance.mayInst.rendered;
  1782. }
  1783. }
  1784. }
  1785. return ret;
  1786. }
  1787. function Component(props, context, key, ref) {
  1788. this.props = props;
  1789. this.key = key;
  1790. this.ref = ref;
  1791. this.context = context;
  1792. //新建个对象存放各种信息
  1793. this.mayInst = {};
  1794. }
  1795. Component.prototype.setState = function (state, callback) {
  1796. var lifeState = this.mayInst.lifeState;
  1797. if (callback) {
  1798. //回调队列调用之前也许sort
  1799. callback = callback.bind(this);
  1800. callback._mountOrder = this.mayInst.mountOrder;
  1801. mayQueue.callbackQueue.push(callback);
  1802. }
  1803. if (this.mayInst.mergeStateQueue) {
  1804. this.mayInst.mergeStateQueue.push(state);
  1805. } else {
  1806. this.mayInst.mergeStateQueue = new Array(state);
  1807. }
  1808. if (mayQueue.isInEvent) {
  1809. //如果在绑定事件中 触发setState合并state
  1810. if (mayQueue.dirtyComponentsQueue.indexOf(this) === -1) {
  1811. this.mayInst.dirty = true;
  1812. mayQueue.dirtyComponentsQueue.push(this);
  1813. }
  1814. return;
  1815. }
  1816. switch (lifeState) {
  1817. //componentWillReceiveProps触发setState会合并state
  1818. case 1: //componentWillMount 触发setState会合并state
  1819. return;
  1820. //ComponentWillReceiveProps 中setState 3
  1821. //子组件在ComponentWillMount中调用父组件的setState 3
  1822. case 3:
  1823. case 2: //componentDidMount 触发setState会放到下一周期 2
  1824. if (mayQueue.dirtyComponentsQueue.indexOf(this) === -1) {
  1825. this.mayInst.dirty = true;
  1826. this.mayInst.needNextRender = true; //子组件componentWillReceiveProps 调用父组件的setState 触发setState会放到下一周期
  1827. mayQueue.dirtyComponentsQueue.push(this);
  1828. }
  1829. return;
  1830. default:
  1831. if (mayQueue.dirtyComponentsQueue.indexOf(this) === -1) {
  1832. this.mayInst.dirty = true;
  1833. mayQueue.dirtyComponentsQueue.push(this);
  1834. }
  1835. break;
  1836. }
  1837. mayQueue.clearQueue();
  1838. };
  1839. Component.prototype.forceUpdate = function (callback) {
  1840. if (callback) {
  1841. mayQueue.callbackQueue.push(callback.bind(this));
  1842. }
  1843. if (mayQueue.dirtyComponentsQueue.indexOf(this) === -1) {
  1844. this.mayInst.forceUpdate = true;
  1845. this.mayInst.dirty = true;
  1846. mayQueue.dirtyComponentsQueue.push(this);
  1847. }
  1848. var lifeState = this.mayInst.lifeState;
  1849. switch (lifeState) {
  1850. case 1: //ComponentWillMount
  1851. case 2: //componentDidMount
  1852. case 3: //ComponentWillReceiveProps
  1853. case 4: //ComponentWillReceiveProps
  1854. return;
  1855. default:
  1856. mayQueue.clearQueue();
  1857. break;
  1858. }
  1859. };
  1860. Component.prototype.isMounted = function () {
  1861. return this.mayInst ? (!!(this.mayInst.rendered && this.mayInst.rendered.mayInfo.hostNode) || this.mayInst.isEmpty) : false;
  1862. };
  1863. function PureComponent(props, key, ref, context) {
  1864. return Component.apply(this, arguments);
  1865. }
  1866. var fn = inherits(PureComponent, Component);
  1867. //返回false 则不进行之后的渲染
  1868. fn.shouldComponentUpdate = function (nextProps, nextState, context) {
  1869. var ret = true;
  1870. var a = shallowEqual(this.props, nextProps);
  1871. var b = shallowEqual(this.state, nextState);
  1872. if (a === true && b === true) {
  1873. ret = false;
  1874. }
  1875. return ret;
  1876. };
  1877. function shallowEqual(now, next) {
  1878. if (Object.is(now, next)) {
  1879. return true;
  1880. }
  1881. //必须是对象
  1882. if ((now && typeof now !== 'object') || (next && typeof next !== 'object')) {
  1883. return false;
  1884. }
  1885. var keysA = Object.keys(now);
  1886. var keysB = Object.keys(next);
  1887. if (keysA.length !== keysB.length) {
  1888. return false;
  1889. }
  1890. // Test for A's keys different from B.
  1891. for (var i = 0; i < keysA.length; i++) {
  1892. if (!hasOwnProperty.call(next, keysA[i]) || !Object.is(now[keysA[i]], next[keysA[i]])) {
  1893. return false;
  1894. }
  1895. }
  1896. return true;
  1897. }
  1898. function cloneElement(element, additionalProps) {
  1899. var type = element.type;
  1900. var props = element.props;
  1901. var mergeProps = {};
  1902. Object.assign(mergeProps, props, additionalProps);
  1903. var config = {};
  1904. if (element.key) {
  1905. config.key = element.key;
  1906. }
  1907. if (element.ref) {
  1908. config.ref = element.ref;
  1909. }
  1910. for (const key in mergeProps) {
  1911. if (key !== 'children') {
  1912. config[key] = mergeProps[key];
  1913. }
  1914. }
  1915. var children = mergeProps.children;
  1916. var ret = createElement(type, config, children);
  1917. return ret;
  1918. }
  1919. const Children = {
  1920. only: function (child) {
  1921. if (child && !Array.isArray(child)) {
  1922. return child;
  1923. }
  1924. if (child && child.length === 1 && child[0].mtype) {
  1925. return child[0];
  1926. }
  1927. throw new Error("expect only one child");
  1928. },
  1929. forEach: function (children, callback, context) {
  1930. var ret;
  1931. if (!children) {
  1932. return null;
  1933. }
  1934. ret = toArray(children);
  1935. ret.forEach(callback, context);
  1936. return ret;
  1937. },
  1938. map: function (children, callback, context) {
  1939. var ret = [];
  1940. if (children == null) {
  1941. //null 或undefinded直接返回
  1942. return children;
  1943. }
  1944. toArray(children).forEach(function (item, index) {
  1945. var res = callback.call(context, item, index);
  1946. if (res == null) {
  1947. return;
  1948. } else {
  1949. ret.push(res);
  1950. }
  1951. });
  1952. return ret;
  1953. },
  1954. toArray: function (children) {
  1955. if (children == null) {
  1956. return [];
  1957. }
  1958. return toArray(children);
  1959. }
  1960. };
  1961. function toArray(children) {
  1962. var ret = [];
  1963. if (Array.isArray(children)) {
  1964. for (var i = 0; i < children.length; i++) {
  1965. var c = children[i];
  1966. if (c.type) {
  1967. ret.push(c);
  1968. } else { //有可能是子数组iterator
  1969. var iteratorFn = getIteractor(c);
  1970. if (iteratorFn) {
  1971. var iterators = callIteractor(iteratorFn, c);
  1972. for (var _i = 0; _i < iterators.length; _i++) {
  1973. ret.push(iterators[_i]);
  1974. }
  1975. } else {
  1976. ret.push(c);
  1977. }
  1978. }
  1979. }
  1980. } else {
  1981. ret.push(children);
  1982. }
  1983. return ret;
  1984. }
  1985. //为了兼容yo
  1986. var check = function () {
  1987. return check;
  1988. };
  1989. check.isRequired = check;
  1990. var PropTypes = {
  1991. array: check,
  1992. bool: check,
  1993. func: check,
  1994. number: check,
  1995. object: check,
  1996. string: check,
  1997. any: check,
  1998. arrayOf: check,
  1999. element: check,
  2000. instanceOf: check,
  2001. node: check,
  2002. objectOf: check,
  2003. oneOf: check,
  2004. oneOfType: check,
  2005. shape: check
  2006. };
  2007. var May = {
  2008. createElement: createElement,
  2009. Component: Component,
  2010. PureComponent: PureComponent,
  2011. cloneElement: cloneElement,
  2012. Children: Children,
  2013. render: render,
  2014. PropTypes: PropTypes,
  2015. findDOMNode: findDOMNode,
  2016. unmountComponentAtNode: unmountComponentAtNode,
  2017. isValidElement: function (vnode) {
  2018. return vnode && vnode.mtype;
  2019. },
  2020. createFactory: function createFactory(type) {
  2021. console.error("createFactory is deprecated");
  2022. var factory = createElement.bind(null, type);
  2023. factory.type = type;
  2024. return factory;
  2025. }
  2026. };
  2027. window.React = window.ReactDOM = May;
  2028. module.exports = May;