123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574 |
- /**
- * by 司徒正美 Copyright 2017-10-23
- * IE9+
- */
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global.React = factory());
- }(this, (function () {
- var innerHTML = "dangerouslySetInnerHTML";
- var emptyArray = [];
- var emptyObject = {};
- function deprecatedWarn(methodName) {
- if (!deprecatedWarn[methodName]) {
- //eslint-disable-next-line
- console.error(methodName + " is deprecated");
- deprecatedWarn[methodName] = 1;
- }
- }
- /**
- * 复制一个对象的属性到另一个对象
- *
- * @param {any} obj
- * @param {any} props
- * @returns
- */
- function extend(obj, props) {
- for (var i in props) {
- if (props.hasOwnProperty(i)) {
- obj[i] = props[i];
- }
- }
- return obj;
- }
- var __type = Object.prototype.toString;
- /**
- * 一个空函数
- *
- * @export
- */
- function noop() {}
- /**
- * 类继承
- *
- * @export
- * @param {any} SubClass
- * @param {any} SupClass
- */
- function inherit(SubClass, SupClass) {
- function Bridge() {}
- Bridge.prototype = SupClass.prototype;
- var fn = SubClass.prototype = new Bridge();
- // 避免原型链拉长导致方法查找的性能开销
- extend(fn, SupClass.prototype);
- fn.constructor = SubClass;
- return fn;
- }
- var lowerCache = {};
- /**
- * 小写化的优化
- *
- * @export
- * @param {any} s
- * @returns
- */
- function toLowerCase(s) {
- return lowerCache[s] || (lowerCache[s] = s.toLowerCase());
- }
- function clearArray(a) {
- return a.splice(0, a.length);
- }
- /**
- *
- *
- * @param {any} obj
- * @returns
- */
- function isFn(obj) {
- return __type.call(obj) === "[object Function]";
- }
- var rword = /[^, ]+/g;
- function oneObject(array, val) {
- if (array + "" === array) {
- //利用字符串的特征进行优化,字符串加上一个空字符串等于自身
- array = array.match(rword) || [];
- }
- var result = {},
- //eslint-disable-next-line
- value = val !== void 666 ? val : 1;
- for (var i = 0, n = array.length; i < n; i++) {
- result[array[i]] = value;
- }
- return result;
- }
- function getChildContext(instance, parentContext) {
- if (instance.getChildContext) {
- var context = instance.getChildContext();
- if (context) {
- parentContext = Object.assign({}, parentContext, context);
- }
- }
- return parentContext;
- }
- function getContextByTypes(curContext, contextTypes) {
- var context = {};
- if (!contextTypes || !curContext) {
- return context;
- }
- for (var key in contextTypes) {
- if (contextTypes.hasOwnProperty(key)) {
- context[key] = curContext[key];
- }
- }
- return context;
- }
- var rcamelize = /[-_][^-_]/g;
- function camelize(target) {
- //提前判断,提高getStyle等的效率
- if (!target || target.indexOf("-") < 0 && target.indexOf("_") < 0) {
- return target;
- }
- //转换为驼峰风格
- var str = target.replace(rcamelize, function (match) {
- return match.charAt(1).toUpperCase();
- });
- return firstLetterLower(str);
- }
- function firstLetterLower(str) {
- return str.charAt(0).toLowerCase() + str.slice(1);
- }
- var options = {
- dirtyComponents: [],
- queue: [],
- beforeUnmount: noop,
- beforeRender: noop,
- beforePatch: noop,
- afterRender: noop,
- afterPatch: noop,
- afterMount: noop,
- afterUpdate: noop
- };
- var numberMap = {
- //null undefined IE6-8这里会返回[object Object]
- "[object Boolean]": 2,
- "[object Number]": 3,
- "[object String]": 4,
- "[object Function]": 5,
- "[object Symbol]": 6,
- "[object Array]": 7
- };
- // undefined: 0, null: 1, boolean:2, number: 3, string: 4, function: 5, symbol:6, array: 7, object:8
- function typeNumber(data) {
- if (data === null) {
- return 1;
- }
- if (data === void 666) {
- return 0;
- }
- var a = numberMap[__type.call(data)];
- return a || 8;
- }
- var recyclables = {
- "#text": []
- };
- //fix 0.14对此方法的改动,之前refs里面保存的是虚拟DOM
- function getDOMNode() {
- return this;
- }
- var pendingRefs = [];
- window.pendingRefs = pendingRefs;
- var Refs = {
- currentOwner: null,
- clearElementRefs: function clearElementRefs() {
- var callback = this.fireRef;
- var refs = pendingRefs.splice(0, pendingRefs.length);
- for (var i = 0, n = refs.length; i < n; i += 2) {
- var vnode = refs[i];
- var data = refs[i + 1];
- callback(vnode, data);
- }
- },
- detachRef: function detachRef(lastVnode, nextVnode, dom) {
- if (lastVnode.ref === nextVnode.ref) {
- return;
- }
- if (lastVnode._hasRef) {
- this.fireRef(lastVnode, null);
- }
- if (nextVnode._hasRef && dom) {
- pendingRefs.push(nextVnode, dom);
- }
- },
- fireRef: function fireRef(vnode, dom) {
- var ref = vnode.ref;
- if (typeof ref === "function") {
- return ref(dom);
- }
- var owner = vnode._owner;
- if (!owner) {
- throw "ref位置错误";
- }
- if (dom) {
- if (dom.nodeType) {
- dom.getDOMNode = getDOMNode;
- }
- owner.refs[ref] = dom;
- } else {
- delete owner.refs[ref];
- }
- }
- };
- /**
- * 创建虚拟DOM
- *
- * @param {string} type
- * @param {object} props
- * @param {array} ...children
- * @returns
- */
- function createElement(type, config) {
- for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
- children[_key - 2] = arguments[_key];
- }
- var props = {},
- checkProps = 0,
- vtype = 1,
- key = null,
- ref = null,
- argsLen = children.length;
- if (type && type.call) {
- vtype = type.prototype && type.prototype.render ? 2 : 4;
- } else if (type + "" !== type) {
- console.error("createElement第一个参数类型错误"); // eslint-disable-line
- }
- if (config != null) {
- for (var i in config) {
- var val = config[i];
- if (i === "key") {
- if (val !== void 0) {
- key = val + "";
- }
- } else if (i === "ref") {
- if (val !== void 0) {
- ref = val;
- }
- } else if (i === "children") {
- props[i] = val;
- } else {
- checkProps = 1;
- props[i] = val;
- }
- }
- }
- if (argsLen === 1) {
- props.children = children[0];
- // : EMPTY_CHILDREN;
- } else if (argsLen > 1) {
- props.children = children;
- }
- var defaultProps = type.defaultProps;
- if (defaultProps) {
- for (var propName in defaultProps) {
- if (props[propName] === void 666) {
- checkProps = 1;
- props[propName] = defaultProps[propName];
- }
- }
- }
- return new Vnode(type, key, ref, props, vtype, checkProps);
- }
- function Vnode(type, key, ref, props, vtype, checkProps) {
- this.type = type;
- this.props = props;
- this.vtype = vtype;
- this._owner = Refs.currentOwner;
- if (key) {
- this.key = key;
- }
- if (vtype === 1) {
- this.checkProps = checkProps;
- }
- var refType = typeNumber(ref);
- if (refType === 3 || refType === 4 || refType === 5) {
- //number, string, function
- this._hasRef = true;
- this.ref = ref;
- }
- /*
- this._hostNode = null
- this._instance = null
- */
- }
- Vnode.prototype = {
- getDOMNode: function getDOMNode() {
- return this._hostNode || null;
- },
- $$typeof: 1
- };
- function flattenChildren(vnode) {
- var arr = emptyArray,
- c = vnode.props.children;
- if (c !== null) {
- arr = _flattenChildren(c, true);
- if (arr.length === 0) {
- arr = emptyArray;
- }
- }
- return vnode.vchildren = arr;
- }
- function _flattenChildren(original, convert) {
- var children = [],
- unidimensionalIndex = 0,
- lastText = void 0,
- child = void 0,
- isMap = convert === "",
- iteractorFn = void 0,
- temp = Array.isArray(original) ? original.slice(0) : [original];
- while (temp.length) {
- if ((child = temp.shift()) && (child.shift || (iteractorFn = getIteractor(child)))) {
- //比较巧妙地判定是否为子数组
- if (iteractorFn) {
- //兼容Immutable.js, Map, Set
- child = callIteractor(iteractorFn, child);
- iteractorFn = false;
- temp.unshift.apply(temp, child);
- continue;
- }
- if (isMap) {
- if (!child._prefix) {
- child._prefix = "." + unidimensionalIndex;
- unidimensionalIndex++; //维护第一层元素的索引值
- }
- for (var i = 0; i < child.length; i++) {
- if (child[i]) {
- child[i]._prefix = child._prefix + ":" + i;
- }
- }
- }
- temp.unshift.apply(temp, child);
- } else {
- var childType = typeNumber(child);
- if (childType < 3) {
- // 0, 1, 2
- if (convert) {
- continue;
- } else {
- child = null;
- }
- } else if (childType < 6) {
- if (lastText && convert) {
- //false模式下不进行合并与转换
- lastText.text += child;
- continue;
- }
- if (convert) {
- child = {
- type: "#text",
- text: child + "",
- vtype: 0
- };
- unidimensionalIndex++;
- }
- lastText = child;
- } else {
- if (isMap && !child._prefix) {
- child._prefix = "." + unidimensionalIndex;
- unidimensionalIndex++;
- }
- if (!child.type) {
- throw Error("这不是一个虚拟DOM");
- }
- lastText = false;
- }
- children.push(child);
- }
- }
- return children;
- }
- var REAL_SYMBOL = typeof Symbol === "function" && Symbol.iterator;
- var FAKE_SYMBOL = "@@iterator";
- function getIteractor(a) {
- if (typeNumber(a) > 7) {
- var iteratorFn = REAL_SYMBOL && a[REAL_SYMBOL] || a[FAKE_SYMBOL];
- if (iteratorFn && iteratorFn.call) {
- return iteratorFn;
- }
- }
- }
- function callIteractor(iteratorFn, children) {
- var iterator = iteratorFn.call(children),
- step,
- ret = [];
- if (iteratorFn !== children.entries) {
- while (!(step = iterator.next()).done) {
- ret.push(step.value);
- }
- } else {
- //Map, Set
- while (!(step = iterator.next()).done) {
- var entry = step.value;
- if (entry) {
- ret.push(entry[1]);
- }
- }
- }
- return ret;
- }
- function cloneElement(vnode, props) {
- if (!vnode.vtype) {
- return extend({}, vnode);
- }
- var owner = vnode._owner,
- lastOwn = Refs.currentOwner,
- old = vnode.props,
- configs = {};
- if (props) {
- Object.assign(configs, old, props);
- configs.key = props.key !== void 666 ? props.key : vnode.key;
- if (props.ref !== void 666) {
- configs.ref = props.ref;
- owner = lastOwn;
- } else if (vnode._hasRef) {
- configs.ref = vnode.ref;
- }
- } else {
- configs = old;
- }
- Refs.currentOwner = owner;
- var args = [].slice.call(arguments, 0),
- argsLength = args.length;
- args[0] = vnode.type;
- args[1] = configs;
- if (argsLength === 2 && configs.children) {
- args.push(configs.children);
- }
- var ret = createElement.apply(null, args);
- Refs.currentOwner = lastOwn;
- return ret;
- }
- var Children = {
- only: function only(children) {
- //only方法接受的参数只能是一个对象,不能是多个对象(数组)。
- if (children && children.vtype) {
- return children;
- }
- throw new Error("expect only one child");
- },
- count: function count(children) {
- if (children == null) {
- return 0;
- }
- return _flattenChildren(children, false).length;
- },
- map: function map(children, callback, context) {
- if (children == null) {
- return children;
- }
- var ret = [];
- _flattenChildren(children, "").forEach(function (old, index) {
- var el = callback.call(context, old, index);
- if (el === null) {
- return;
- }
- if (el.vtype) {
- //如果返回的el等于old,还需要使用原来的key, _prefix
- var key = computeKey(old, el, index);
- ret.push(cloneElement(el, { key: key }));
- } else if (el.type) {
- ret.push(extend({}, el));
- } else {
- ret.push(el);
- }
- });
- return ret;
- },
- forEach: function forEach(children, callback, context) {
- if (children != null) {
- _flattenChildren(children, false).forEach(callback, context);
- }
- },
- toArray: function toArray(children) {
- if (children == null) {
- return [];
- }
- return Children.map(children, function (el) {
- return el;
- });
- }
- };
- var rthimNumer = /\d+\$/;
- function computeKey(old, el, index) {
- var curKey = el && el.key != null ? escapeKey(el.key) : null;
- var oldKey = old && old.key != null ? escapeKey(old.key) : null;
- var oldFix = old && old._prefix,
- key = void 0;
- if (oldKey && curKey) {
- key = oldFix + "$" + oldKey;
- if (oldKey !== curKey) {
- key = curKey + "/" + key;
- }
- } else {
- key = curKey || oldKey;
- if (key) {
- if (oldFix) {
- key = oldFix + "$" + key;
- }
- } else {
- key = oldFix || "." + index;
- }
- }
- return key.replace(rthimNumer, "$");
- }
- function escapeKey(key) {
- return String(key).replace(/[=:]/g, escaperFn);
- }
- var escaperLookup = {
- "=": "=0",
- ":": "=2"
- };
- function escaperFn(match) {
- return escaperLookup[match];
- }
- //用于后端的元素节点
- function DOMElement(type) {
- this.nodeName = type;
- this.style = {};
- this.children = [];
- }
- var NAMESPACE = {
- svg: "http://www.w3.org/2000/svg",
- xmlns: "http://www.w3.org/2000/xmlns/",
- xlink: "http://www.w3.org/1999/xlink",
- math: "http://www.w3.org/1998/Math/MathML",
- xhtml: "http://www.w3.org/1999/xhtml",
- html: "https://www.w3.org/TR/html4/"
- };
- var fn = DOMElement.prototype = {
- contains: Boolean
- };
- String("replaceChild,appendChild,removeAttributeNS,setAttributeNS,removeAttribute,setAttribute" + ",getAttribute,insertBefore,removeChild,addEventListener,removeEventListener,attachEvent" + ",detachEvent").replace(/\w+/g, function (name) {
- fn[name] = function () {
- console.log("fire " + name); // eslint-disable-line
- };
- });
- //用于后端的document
- var fakeDoc = new DOMElement();
- fakeDoc.createElement = fakeDoc.createElementNS = fakeDoc.createDocumentFragment = function (type) {
- return new DOMElement(type);
- };
- fakeDoc.createTextNode = fakeDoc.createComment = Boolean;
- fakeDoc.documentElement = new DOMElement("html");
- fakeDoc.nodeName = "#document";
- fakeDoc.textContent = "";
- try {
- var w = window;
- var b = !!w.alert;
- } catch (e) {
- b = false;
- w = {
- document: fakeDoc
- };
- }
- var win = w;
- var document = w.document || fakeDoc;
- var isStandard = "textContent" in document;
- var fragment = document.createDocumentFragment();
- function emptyElement(node) {
- var child;
- while (child = node.firstChild) {
- emptyElement(child);
- node.removeChild(child);
- }
- }
- function removeElement(node) {
- if (node.nodeType === 1) {
- if (isStandard) {
- node.textContent = "";
- } else {
- emptyElement(node);
- }
- node.__events = null;
- } else if (node.nodeType === 3) {
- //只回收文本节点
- if (recyclables["#text"].length < 100) {
- recyclables["#text"].push(node);
- }
- }
- fragment.appendChild(node);
- fragment.removeChild(node);
- }
- var versions = {
- 88: 7, //IE7-8 objectobject
- 80: 6, //IE6 objectundefined
- "00": NaN, // other modern browsers
- "08": NaN
- };
- /* istanbul ignore next */
- var msie = document.documentMode || versions[typeNumber(document.all) + "" + typeNumber(XMLHttpRequest)];
- var modern = /NaN|undefined/.test(msie) || msie > 8;
- function insertElement(container, target, insertPoint) {
- if (insertPoint) {
- container.insertBefore(target, insertPoint);
- } else {
- container.appendChild(target);
- }
- }
- function createElement$1(vnode, vparent) {
- var type = vnode.type;
- if (type === "#text") {
- //只重复利用文本节点
- var node = recyclables[type].pop();
- if (node) {
- node.nodeValue = vnode.text;
- return node;
- }
- return document.createTextNode(vnode.text);
- }
- if (type === "#comment") {
- return document.createComment(vnode.text);
- }
- var check = vparent || vnode;
- var ns = check.namespaceURI;
- if (type === "svg") {
- ns = NAMESPACE.svg;
- } else if (type === "math") {
- ns = NAMESPACE.math;
- } else if (check.type.toLowerCase() === "foreignobject" || !ns || ns === NAMESPACE.html || ns === NAMESPACE.xhtml) {
- return document.createElement(type);
- }
- try {
- vnode.namespaceURI = ns;
- return document.createElementNS(ns, type);
- //eslint-disable-next-line
- } catch (e) {
- return document.createElement(type);
- }
- }
- var globalEvents = {};
- var eventPropHooks = {}; //用于在事件回调里对事件对象进行
- var eventHooks = {}; //用于在元素上绑定特定的事件
- //根据onXXX得到其全小写的事件名, onClick --> click, onClickCapture --> click,
- // onMouseMove --> mousemove
- var eventLowerCache = {
- onClick: "click",
- onChange: "change",
- onWheel: "wheel"
- };
- /**
- * 判定否为与事件相关
- *
- * @param {any} name
- * @returns
- */
- function isEventName(name) {
- return (/^on[A-Z]/.test(name)
- );
- }
- var isTouch = "ontouchstart" in document;
- function dispatchEvent(e, type, end) {
- //__type__ 在injectTapEventPlugin里用到
- e = new SyntheticEvent(e);
- if (type) {
- e.type = type;
- }
- var bubble = e.type;
- var hook = eventPropHooks[bubble];
- if (hook && false === hook(e)) {
- return;
- }
- var paths = collectPaths(e.target, end || document);
- var captured = bubble + "capture";
- options.async = true;
- if (options.async) {
- var cur = options.queue;
- if (cur !== options.dirtyComponents) {
- options.queue = options.dirtyComponents;
- options.queue.last = cur;
- }
- }
- triggerEventFlow(paths, captured, e);
- if (!e._stopPropagation) {
- triggerEventFlow(paths.reverse(), bubble, e);
- }
- options.async = false;
- options.flushUpdaters();
- }
- function collectPaths(from, end) {
- var paths = [];
- do {
- if (from === end) {
- break;
- }
- var events = from.__events;
- if (events) {
- paths.push({ dom: from, events: events });
- }
- } while ((from = from.parentNode) && from.nodeType === 1);
- // target --> parentNode --> body --> html
- return paths;
- }
- function triggerEventFlow(paths, prop, e) {
- for (var i = paths.length; i--;) {
- var path = paths[i];
- var fn = path.events[prop];
- if (isFn(fn)) {
- e.currentTarget = path.dom;
- fn.call(path.dom, e);
- if (e._stopPropagation) {
- break;
- }
- }
- }
- }
- function addGlobalEvent(name) {
- if (!globalEvents[name]) {
- globalEvents[name] = true;
- addEvent(document, name, dispatchEvent);
- }
- }
- function addEvent(el, type, fn, bool) {
- if (el.addEventListener) {
- el.addEventListener(type, fn, bool || false);
- } else if (el.attachEvent) {
- el.attachEvent("on" + type, fn);
- }
- }
- var rcapture = /Capture$/;
- function getBrowserName(onStr) {
- var lower = eventLowerCache[onStr];
- if (lower) {
- return lower;
- }
- var camel = onStr.slice(2).replace(rcapture, "");
- lower = camel.toLowerCase();
- eventLowerCache[onStr] = lower;
- return lower;
- }
- eventPropHooks.click = function (e) {
- return !e.target.disabled;
- };
- /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
- firefox DOMMouseScroll detail 下3 上-3
- firefox wheel detlaY 下3 上-3
- IE9-11 wheel deltaY 下40 上-40
- chrome wheel deltaY 下100 上-100 */
- /* istanbul ignore next */
- var fixWheelType = "onmousewheel" in document ? "mousewheel" : document.onwheel !== void 666 ? "wheel" : "DOMMouseScroll";
- var fixWheelDelta = fixWheelType === "mousewheel" ? "wheelDetla" : fixWheelType === "wheel" ? "deltaY" : "detail";
- eventHooks.wheel = function (dom) {
- addEvent(dom, fixWheelType, function (e) {
- var delta = e[fixWheelDelta] > 0 ? -120 : 120;
- var deltaY = ~~dom.__wheel + delta;
- dom.__wheel = deltaY;
- e = new SyntheticEvent(e);
- e.type = "wheel";
- e.deltaY = deltaY;
- dispatchEvent(e);
- });
- };
- var fixFocus = {};
- "blur,focus".replace(/\w+/g, function (type) {
- eventHooks[type] = function () {
- if (!fixFocus[type]) {
- fixFocus[type] = true;
- addEvent(document, type, dispatchEvent, true);
- }
- };
- });
- /**
- *
- DOM通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;
- 对于其他事件,这个属性的值是null。IE不支持realtedTarget属性,但提供了保存着同样信息的不同属性。
- 在mouseover事件触发时,IE的fromElement属性中保存了相关元素;
- 在mouseout事件出发时,IE的toElement属性中保存着相关元素。
- 但fromElement与toElement可能同时都有值
- */
- function getRelatedTarget(e) {
- if (!e.timeStamp) {
- e.relatedTarget = e.type === "mouseover" ? e.fromElement : e.toElement;
- }
- return e.relatedTarget;
- }
- function contains(a, b) {
- if (b) {
- while (b = b.parentNode) {
- if (b === a) {
- return true;
- }
- }
- }
- return false;
- }
- String("mouseenter,mouseleave").replace(/\w+/g, function (type) {
- eventHooks[type] = function (dom, name) {
- var mark = "__" + name;
- if (!dom[mark]) {
- dom[mark] = true;
- var mask = name === "mouseenter" ? "mouseover" : "mouseout";
- addEvent(dom, mask, function (e) {
- var t = getRelatedTarget(e);
- if (!t || t !== dom && !contains(dom, t)) {
- var common = getLowestCommonAncestor(dom, t);
- //由于不冒泡,因此paths长度为1
- dispatchEvent(e, name, common);
- }
- });
- }
- };
- });
- function getLowestCommonAncestor(instA, instB) {
- var depthA = 0;
- for (var tempA = instA; tempA; tempA = tempA.parentNode) {
- depthA++;
- }
- var depthB = 0;
- for (var tempB = instB; tempB; tempB = tempB.parentNode) {
- depthB++;
- }
- // If A is deeper, crawl up.
- while (depthA - depthB > 0) {
- instA = instA.parentNode;
- depthA--;
- }
- // If B is deeper, crawl up.
- while (depthB - depthA > 0) {
- instB = instB.parentNode;
- depthB--;
- }
- // Walk in lockstep until we find a match.
- var depth = depthA;
- while (depth--) {
- if (instA === instB) {
- return instA;
- }
- instA = instA.parentNode;
- instB = instB.parentNode;
- }
- return null;
- }
- if (isTouch) {
- eventHooks.click = noop;
- eventHooks.clickcapture = noop;
- }
- function createHandle(name, fn) {
- return function (e) {
- if (fn && fn(e) === false) {
- return;
- }
- dispatchEvent(e, name);
- };
- }
- var changeHandle = createHandle("change");
- var doubleClickHandle = createHandle("doubleclick");
- //react将text,textarea,password元素中的onChange事件当成onInput事件
- eventHooks.changecapture = eventHooks.change = function (dom) {
- if (/text|password/.test(dom.type)) {
- addEvent(document, "input", changeHandle);
- }
- };
- eventHooks.doubleclick = eventHooks.doubleclickcapture = function () {
- addEvent(document, "dblclick", doubleClickHandle);
- };
- function SyntheticEvent(event) {
- if (event.nativeEvent) {
- return event;
- }
- for (var i in event) {
- if (!eventProto[i]) {
- this[i] = event[i];
- }
- }
- if (!this.target) {
- this.target = event.srcElement;
- }
- this.fixEvent();
- this.timeStamp = new Date() - 0;
- this.nativeEvent = event;
- }
- var eventProto = SyntheticEvent.prototype = {
- fixEvent: function fixEvent() {}, //留给以后扩展用
- preventDefault: function preventDefault() {
- var e = this.nativeEvent || {};
- e.returnValue = this.returnValue = false;
- if (e.preventDefault) {
- e.preventDefault();
- }
- },
- fixHooks: function fixHooks() {},
- stopPropagation: function stopPropagation() {
- var e = this.nativeEvent || {};
- e.cancelBubble = this._stopPropagation = true;
- if (e.stopPropagation) {
- e.stopPropagation();
- }
- },
- persist: noop,
- stopImmediatePropagation: function stopImmediatePropagation() {
- this.stopPropagation();
- this.stopImmediate = true;
- },
- toString: function toString() {
- return "[object Event]";
- }
- };
- /* istanbul ignore next */
- var eventSystem = extend({
- eventPropHooks: eventPropHooks,
- eventHooks: eventHooks,
- eventLowerCache: eventLowerCache,
- isEventName: isEventName,
- isTouch: isTouch,
- dispatchEvent: dispatchEvent,
- addGlobalEvent: addGlobalEvent,
- addEvent: addEvent,
- getBrowserName: getBrowserName,
- createHandle: createHandle,
- SyntheticEvent: SyntheticEvent
- });
- //为了兼容yo
- var check = function check() {
- return check;
- };
- check.isRequired = check;
- var PropTypes = {
- array: check,
- bool: check,
- func: check,
- number: check,
- object: check,
- string: check,
- any: check,
- arrayOf: check,
- element: check,
- instanceOf: check,
- node: check,
- objectOf: check,
- oneOf: check,
- oneOfType: check,
- shape: check
- };
- /**
- *组件的基类
- *
- * @param {any} props
- * @param {any} context
- */
- function Component(props, context) {
- //防止用户在构造器生成JSX
- Refs.currentOwner = this;
- this.context = context;
- this.props = props;
- this.refs = {};
- this.state = null;
- }
- Component.prototype = {
- constructor: Component, //必须重写constructor,防止别人在子类中使用Object.getPrototypeOf时找不到正确的基类
- replaceState: function replaceState() {
- deprecatedWarn("replaceState");
- },
- setState: function setState(state, cb) {
- debounceSetState(this.updater, state, cb);
- },
- isMounted: function isMounted() {
- deprecatedWarn("isMounted");
- return !!(this.updater || emptyObject)._hostNode;
- },
- forceUpdate: function forceUpdate(cb) {
- debounceSetState(this.updater, true, cb);
- },
- render: function render() {}
- };
- function debounceSetState(updater, state, cb) {
- if (!updater) {
- return;
- }
- if (updater._didUpdate) {
- //如果用户在componentDidUpdate中使用setState,要防止其卡死
- setTimeout(function () {
- updater._didUpdate = false;
- setStateImpl(updater, state, cb);
- }, 300);
- return;
- }
- setStateImpl(updater, state, cb);
- }
- function setStateImpl(updater, state, cb) {
- if (isFn(cb)) {
- updater._pendingCallbacks.push(cb);
- }
- if (state === true) {
- //forceUpdate
- updater._forceUpdate = true;
- } else {
- //setState
- updater._pendingStates.push(state);
- }
- if (updater._lifeStage == 0) {
- //组件挂载期
- //componentWillUpdate中的setState/forceUpdate应该被忽略
- if (updater._hydrating) {
- //在render方法中调用setState也会被延迟到下一周期更新.这存在两种情况,
- //1. 组件直接调用自己的setState
- //2. 子组件调用父组件的setState,
- updater._renderInNextCycle = true;
- }
- } else {
- //组件更新期
- if (updater._receiving) {
- //componentWillReceiveProps中的setState/forceUpdate应该被忽略
- return;
- }
- updater._renderInNextCycle = true;
- if (options.async) {
- //在事件句柄中执行setState会进行合并
- options.enqueueUpdater(updater);
- return;
- }
- if (updater._hydrating) {
- // 在componentDidMount里调用自己的setState,延迟到下一周期更新
- // 在更新过程中, 子组件在componentWillReceiveProps里调用父组件的setState,延迟到下一周期更新
- return;
- }
- // 不在生命周期钩子内执行setState
- var last = options.queue;
- var cur = options.queue = [updater];
- cur.last = last;
- options.flushUpdaters(cur);
- options.queue = cur.last || [];
- }
- }
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
- /**
- * 为了兼容0.13之前的版本
- */
- var NOBIND = {
- render: 1,
- shouldComponentUpdate: 1,
- componentWillReceiveProps: 1,
- componentWillUpdate: 1,
- componentDidUpdate: 1,
- componentWillMount: 1,
- componentDidMount: 1,
- componentWillUnmount: 1,
- componentDidUnmount: 1
- };
- function collectMixins(mixins) {
- var keyed = {};
- for (var i = 0; i < mixins.length; i++) {
- var mixin = mixins[i];
- if (mixin.mixins) {
- applyMixins(mixin, collectMixins(mixin.mixins));
- }
- for (var key in mixin) {
- if (mixin.hasOwnProperty(key) && key !== "mixins") {
- (keyed[key] || (keyed[key] = [])).push(mixin[key]);
- }
- }
- }
- return keyed;
- }
- var MANY_MERGED = {
- getInitialState: 1,
- getDefaultProps: 1,
- getChildContext: 1
- };
- function flattenHooks(key, hooks) {
- var hookType = _typeof(hooks[0]);
- if (hookType === "object") {
- // Merge objects
- hooks.unshift({});
- return Object.assign.apply(null, hooks);
- } else if (hookType === "function" && hooks.length > 1) {
- return function () {
- var ret = {},
- r = void 0,
- hasReturn = MANY_MERGED[key];
- for (var i = 0; i < hooks.length; i++) {
- r = hooks[i].apply(this, arguments);
- if (hasReturn && r) {
- Object.assign(ret, r);
- }
- }
- if (hasReturn) {
- return ret;
- }
- return r;
- };
- } else {
- return hooks[0];
- }
- }
- function applyMixins(proto, mixins) {
- for (var key in mixins) {
- if (mixins.hasOwnProperty(key)) {
- proto[key] = flattenHooks(key, mixins[key].concat(proto[key] || []));
- }
- }
- }
- //创建一个构造器
- function newCtor(className, spec) {
- var curry = Function("ReactComponent", "blacklist", "spec", "return function " + className + "(props, context) {\n ReactComponent.call(this, props, context);\n\n for (var methodName in this) {\n var method = this[methodName];\n if (typeof method === \"function\"&& !blacklist[methodName]) {\n this[methodName] = method.bind(this);\n }\n }\n\n if (spec.getInitialState) {\n var test = this.state = spec.getInitialState.call(this);\n if(!(test === null || ({}).toString.call(test) == \"[object Object]\")){\n throw \"getInitialState(): must return an object or null\"\n }\n }\n\n };");
- return curry(Component, NOBIND, spec);
- }
- function createClass(spec) {
- deprecatedWarn("createClass");
- if (!isFn(spec.render)) {
- throw "请实现render方法";
- }
- var Constructor = newCtor(spec.displayName || "Component", spec);
- var proto = inherit(Constructor, Component);
- //如果mixins里面非常复杂,可能mixin还包含其他mixin
- if (spec.mixins) {
- applyMixins(spec, collectMixins(spec.mixins));
- }
- extend(proto, spec);
- if (spec.statics) {
- extend(Constructor, spec.statics);
- }
- "propTypes,contextTypes,childContextTypes,displayName".replace(/\w+/g, function (name) {
- if (spec[name]) {
- var props = Constructor[name] = spec[name];
- if (name !== "displayName") {
- for (var i in props) {
- if (!isFn(props[i])) {
- console.error(i + " in " + name + " must be a function"); // eslint-disable-line
- }
- }
- }
- }
- });
- if (isFn(spec.getDefaultProps)) {
- Constructor.defaultProps = spec.getDefaultProps();
- }
- return Constructor;
- }
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- function shallowEqual(objA, objB) {
- if (Object.is(objA, objB)) {
- return true;
- }
- //确保objA, objB都是对象
- if (typeNumber(objA) < 7 || typeNumber(objB) < 7) {
- return false;
- }
- var keysA = Object.keys(objA);
- var keysB = Object.keys(objB);
- if (keysA.length !== keysB.length) {
- return false;
- }
- // Test for A's keys different from B.
- for (var i = 0; i < keysA.length; i++) {
- if (!hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
- return false;
- }
- }
- return true;
- }
- function PureComponent(props, context) {
- Component.call(this, props, context);
- }
- var fn$1 = inherit(PureComponent, Component);
- fn$1.shouldComponentUpdate = function shallowCompare(nextProps, nextState) {
- var a = shallowEqual(this.props, nextProps);
- var b = shallowEqual(this.state, nextState);
- return !a || !b;
- };
- fn$1.isPureComponent = true;
- var rnumber = /^-?\d+(\.\d+)?$/;
- /**
- * 为元素样子设置样式
- *
- * @export
- * @param {any} dom
- * @param {any} lastStyle
- * @param {any} nextStyle
- */
- function patchStyle(dom, lastStyle, nextStyle) {
- if (lastStyle === nextStyle) {
- return;
- }
- for (var name in nextStyle) {
- var val = nextStyle[name];
- if (lastStyle[name] !== val) {
- name = cssName(name, dom);
- if (val !== 0 && !val) {
- val = ""; //清除样式
- } else if (rnumber.test(val) && !cssNumber[name]) {
- val = val + "px"; //添加单位
- }
- try {
- //node.style.width = NaN;node.style.width = 'xxxxxxx';
- //node.style.width = undefine 在旧式IE下会抛异常
- dom.style[name] = val; //应用样式
- } catch (e) {
- console.log("dom.style[" + name + "] = " + val + "throw error"); // eslint-disable-line
- }
- }
- }
- // 如果旧样式存在,但新样式已经去掉
- for (var _name in lastStyle) {
- if (!(_name in nextStyle)) {
- _name = cssName(_name, dom);
- dom.style[_name] = ""; //清除样式
- }
- }
- }
- var cssNumber = oneObject("animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom");
- //var testStyle = document.documentElement.style
- var prefixes = ["", "-webkit-", "-o-", "-moz-", "-ms-"];
- var cssMap = oneObject("float", "cssFloat");
- /**
- * 转换成当前浏览器可用的样式名
- *
- * @param {any} name
- * @returns
- */
- function cssName(name, dom) {
- if (cssMap[name]) {
- return cssMap[name];
- }
- var host = dom && dom.style || {};
- for (var i = 0, n = prefixes.length; i < n; i++) {
- var camelCase = camelize(prefixes[i] + name);
- if (camelCase in host) {
- return cssMap[name] = camelCase;
- }
- }
- return null;
- }
- function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
- //布尔属性的值末必为true,false
- //https://github.com/facebook/react/issues/10589
- var controlled = {
- value: 1,
- defaultValue: 1
- };
- var isSpecialAttr = {
- style: 1,
- children: 1,
- innerHTML: 1,
- dangerouslySetInnerHTML: 1
- };
- var svgCache = {};
- var strategyCache = {};
- /**
- * 仅匹配 svg 属性名中的第一个驼峰处,如 viewBox 中的 wB,
- * 数字表示该特征在属性列表中重复的次数
- * -1 表示用 ":" 隔开的属性 (xlink:href, xlink:title 等)
- * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
- */
- var svgCamelCase = {
- w: { r: 1, b: 1, t: 1 },
- e: { n: 1, t: 1, f: 1, p: 1, c: 1, m: 1, a: 2, u: 1, s: 1, v: 1 },
- o: { r: 1 },
- c: { m: 1 },
- p: { p: 1 },
- t: { s: 2, t: 1, u: 1, c: 1, d: 1, o: 1, x: 1, y: 1, l: 1 },
- l: { r: 1, m: 1, u: 1, b: -1, l: -1, s: -1 },
- r: { r: 1, u: 2, h: 1, w: 1, c: 1, e: 1 },
- h: { r: 1, a: 1, l: 1, t: 1 },
- y: { p: 1, s: 1, t: 1, c: 1 },
- g: { c: 1 },
- k: { a: -1, h: -1, r: -1, s: -1, t: -1, c: 1, u: 1 },
- m: { o: 1, l: 1, a: 1 },
- n: { c: 1, t: 1, u: 1 },
- s: { a: 3 },
- f: { x: 1, y: 1 },
- d: { e: 1, f: 1, m: 1, d: 1 },
- x: { c: 1 }
- };
- // SVG 属性列表中驼峰命名和短横线分隔命名特征值有重复
- // 列出了重复特征中的短横线命名的属性名
- var specialSVGPropertyName = {
- "overline-thickness": 2,
- "underline-thickness": 2,
- "overline-position": 2,
- "underline-position": 2,
- "stroke-miterlimit": 2,
- "baseline-shift": 2,
- "clip-path": 2,
- "font-size": 2,
- "font-size-adjust": 2,
- "font-stretch": 2,
- "font-style": 2,
- "text-decoration": 2,
- "vert-origin-x": 2,
- "vert-origin-y": 2,
- "paint-order": 2,
- "fill-rule": 2,
- "color-rendering": 2,
- "marker-end": 2,
- "pointer-events": 2,
- "units-per-em": 2,
- "strikethrough-thickness": 2,
- "lighting-color": 2
- };
- // 重复属性名的特征值列表
- var repeatedKey = ["et", "ep", "em", "es", "pp", "ts", "td", "to", "lr", "rr", "re", "ht", "gc"];
- function createRepaceFn(split) {
- return function (match) {
- return match.slice(0, 1) + split + match.slice(1).toLowerCase();
- };
- }
- var rhump = /[a-z][A-Z]/;
- var toHyphen = createRepaceFn("-");
- var toColon = createRepaceFn(":");
- function getSVGAttributeName(name) {
- if (svgCache[name]) {
- return svgCache[name];
- }
- var key = name.match(rhump);
- if (!key) {
- return svgCache[name] = name;
- }
- var _ref = [].concat(_toConsumableArray(key[0].toLowerCase())),
- prefix = _ref[0],
- postfix = _ref[1];
- var orig = name;
- if (svgCamelCase[prefix] && svgCamelCase[prefix][postfix]) {
- var count = svgCamelCase[prefix][postfix];
- if (count === -1) {
- return svgCache[orig] = {
- name: name.replace(rhump, toColon),
- ifSpecial: true
- };
- }
- if (~repeatedKey.indexOf(prefix + postfix)) {
- var dashName = name.replace(rhump, toHyphen);
- if (specialSVGPropertyName[dashName]) {
- name = dashName;
- }
- }
- } else {
- name = name.replace(rhump, toHyphen);
- }
- return svgCache[orig] = name;
- }
- function diffProps(dom, lastProps, nextProps, vnode) {
- var isSVG = vnode.namespaceURI === NAMESPACE.svg;
- var tag = vnode.type;
- //eslint-disable-next-line
- for (var name in nextProps) {
- var val = nextProps[name];
- if (val !== lastProps[name]) {
- var which = tag + isSVG + name;
- var action = strategyCache[which];
- if (!action) {
- action = strategyCache[which] = getPropAction(dom, name, isSVG);
- }
- actionStrategy[action](dom, name, val, lastProps);
- }
- }
- //如果旧属性在新属性对象不存在,那么移除DOM eslint-disable-next-line
- for (var _name in lastProps) {
- if (!nextProps.hasOwnProperty(_name)) {
- var _which = tag + isSVG + _name;
- var _action = strategyCache[_which];
- actionStrategy[_action](dom, _name, false, lastProps);
- }
- }
- }
- function isBooleanAttr(dom, name) {
- var val = dom[name];
- return val === true || val === false;
- }
- /**
- * 根据一个属性所在的元素或元素的文档类型,就可以永久决定该使用什么策略操作它
- *
- * @param {any} dom 元素节点
- * @param {any} name 属性名
- * @param {any} isSVG
- * @returns
- */
- function getPropAction(dom, name, isSVG) {
- if (isSVG && name === "className") {
- return "svgClass";
- }
- if (isSpecialAttr[name]) {
- return name;
- }
- if (isEventName(name)) {
- return "event";
- }
- if (isSVG) {
- return "svgAttr";
- }
- if (isBooleanAttr(dom, name)) {
- return "booleanAttr";
- }
- return name.indexOf("data-") === 0 || dom[name] === void 666 ? "attribute" : "property";
- }
- var builtinStringProps = {
- className: 1,
- title: 1,
- name: 1,
- alt: 1,
- lang: 1,
- value: 1
- };
- var actionStrategy = {
- innerHTML: noop,
- children: noop,
- style: function style(dom, _, val, lastProps) {
- patchStyle(dom, lastProps.style || emptyObject, val || emptyObject);
- },
- svgClass: function svgClass(dom, name, val) {
- if (!val) {
- dom.removeAttribute("class");
- } else {
- dom.setAttribute("class", val);
- }
- },
- svgAttr: function svgAttr(dom, name, val) {
- // http://www.w3school.com.cn/xlink/xlink_reference.asp
- // https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#notable-enh
- // a ncements xlinkActuate, xlinkArcrole, xlinkHref, xlinkRole, xlinkShow,
- // xlinkTitle, xlinkType eslint-disable-next-line
- var method = typeNumber(val) < 3 && !val ? "removeAttribute" : "setAttribute";
- var nameRes = getSVGAttributeName(name);
- if (nameRes.ifSpecial) {
- var prefix = nameRes.name.split(":")[0];
- // 将xlinkHref 转换为 xlink:href
- dom[method + "NS"](NAMESPACE[prefix], nameRes.name, val || "");
- } else {
- dom[method](nameRes, val || "");
- }
- },
- booleanAttr: function booleanAttr(dom, name, val) {
- // 布尔属性必须使用el.xxx = true|false方式设值 如果为false, IE全系列下相当于setAttribute(xxx,""),
- // 会影响到样式,需要进一步处理 eslint-disable-next-line
- dom[name] = !!val;
- if (dom[name] === false) {
- dom.removeAttribute(name);
- } else if (dom[name] === "false") {
- //字符串属性会将它转换为false
- dom[name] = "";
- }
- },
- attribute: function attribute(dom, name, val) {
- if (val == null || val === false) {
- return dom.removeAttribute(name);
- }
- try {
- dom.setAttribute(name, val);
- } catch (e) {
- console.warn("setAttribute error", name, val); // eslint-disable-line
- }
- },
- property: function property(dom, name, val) {
- if (name !== "value" || dom[name] !== val) {
- // 尝试直接赋值,部分情况下会失败,如给 input 元素的 size 属性赋值 0 或字符串
- // 这时如果用 setAttribute 则会静默失败
- try {
- if (!val && val !== 0) {
- //如果它是字符串属性,并且不等于"",清空
- // if (typeNumber(dom[name]) === 4 && dom[name] !== "") {
- if (builtinStringProps[name]) {
- dom[name] = "";
- }
- // }
- dom.removeAttribute(name);
- } else {
- dom[name] = val;
- }
- } catch (e) {
- dom.setAttribute(name, val);
- }
- if (controlled[name]) {
- dom._lastValue = val;
- }
- }
- },
- event: function event(dom, name, val, lastProps) {
- var events = dom.__events || (dom.__events = {});
- var refName = toLowerCase(name.slice(2));
- if (val === false) {
- delete events[refName];
- } else {
- if (!lastProps[name]) {
- //添加全局监听事件
- var eventName = getBrowserName(name);
- var hook = eventHooks[eventName];
- addGlobalEvent(eventName);
- if (hook) {
- hook(dom, eventName);
- }
- }
- //onClick --> click, onClickCapture --> clickcapture
- events[refName] = val;
- }
- },
- dangerouslySetInnerHTML: function dangerouslySetInnerHTML(dom, name, val, lastProps) {
- var oldhtml = lastProps[name] && lastProps[name].__html;
- var html = val && val.__html;
- if (html !== oldhtml) {
- dom.innerHTML = html;
- }
- }
- };
- function disposeVnode(vnode) {
- if (!vnode || vnode._disposed) {
- return;
- }
- var instance = vnode._instance;
- if (vnode._hasRef) {
- vnode._hasRef = false;
- Refs.fireRef(vnode, null);
- }
- if (instance) {
- disposeComponent(vnode, instance);
- } else if (vnode.vtype === 1) {
- disposeElement(vnode);
- }
- vnode._disposed = true;
- }
- function disposeElement(vnode) {
- var props = vnode.props,
- vchildren = vnode.vchildren;
- if (props[innerHTML]) {
- removeElement(vnode._hostNode);
- } else {
- for (var i = 0, n = vchildren.length; i < n; i++) {
- disposeVnode(vchildren[i]);
- }
- vchildren.length = 0;
- }
- }
- function disposeComponent(vnode, instance) {
- options.beforeUnmount(instance);
- instance.setState = instance.forceUpdate = noop;
- if (instance.componentWillUnmount) {
- instance.componentWillUnmount();
- }
- var updater = instance.updater;
- //在执行componentWillUnmount后才将关联的元素节点解绑,防止用户在钩子里调用 findDOMNode方法
- disposeVnode(updater.rendered);
- updater._renderInNextCycle = vnode._instance = instance.updater = null;
- }
- /**
- input, select, textarea这几个元素如果指定了value/checked的**状态属性**,就会包装成受控组件或非受控组件
- 受控组件是指,用户除了为它指定**状态属性**,还为它指定了onChange/onInput/disabled等用于控制此状态属性
- 变动的属性
- 反之,它就是非受控组件,非受控组件会在框架内部添加一些事件,阻止**状态属性**被用户的行为改变,只能被setState改变
- */
- var duplexData = {
- 1: ["value", {
- onChange: 1,
- onInput: 1,
- readOnly: 1,
- disabled: 1
- }, "oninput", preventUserInput],
- 2: ["checked", {
- onChange: 1,
- onClick: 1,
- readOnly: 1,
- disabled: 1
- }, "onclick", preventUserClick],
- 3: ["value", {
- onChange: 1,
- disabled: 1
- }, "onchange", preventUserChange]
- };
- var duplexMap = {
- color: 1,
- date: 1,
- datetime: 1,
- "datetime-local": 1,
- email: 1,
- month: 1,
- number: 1,
- password: 1,
- range: 1,
- search: 1,
- tel: 1,
- text: 1,
- time: 1,
- url: 1,
- week: 1,
- textarea: 1,
- checkbox: 2,
- radio: 2,
- "select-one": 3,
- "select-multiple": 3
- };
- function processFormElement(vnode, dom, props) {
- var domType = dom.type;
- var duplexType = duplexMap[domType];
- if (duplexType) {
- var data = duplexData[duplexType];
- var duplexProp = data[0];
- var keys = data[1];
- var eventName = data[2];
- if (duplexProp in props && !hasOtherControllProperty(props, keys)) {
- // eslint-disable-next-line
- console.warn("\u4F60\u4E3A" + vnode.type + "[type=" + domType + "]\u5143\u7D20\u6307\u5B9A\u4E86" + duplexProp + "\u5C5E\u6027\uFF0C\n \u4F46\u662F\u6CA1\u6709\u63D0\u4F9B\u53E6\u5916\u7684" + Object.keys(keys) + "\u6765\u63A7\u5236" + duplexProp + "\u5C5E\u6027\u7684\u53D8\u5316\n \u90A3\u4E48\u5B83\u5373\u4E3A\u4E00\u4E2A\u975E\u53D7\u63A7\u7EC4\u4EF6\uFF0C\u7528\u6237\u65E0\u6CD5\u901A\u8FC7\u8F93\u5165\u6539\u53D8\u5143\u7D20\u7684" + duplexProp + "\u503C");
- dom[eventName] = data[3];
- }
- if (duplexType === 3) {
- postUpdateSelectedOptions(vnode, dom);
- }
- } else {
- dom.duplexValue = props.value === undefined ? typeNumber(props.children) > 4 ? dom.text : props.children : props.value;
- }
- }
- function hasOtherControllProperty(props, keys) {
- for (var key in props) {
- if (keys[key]) {
- return true;
- }
- }
- }
- function preventUserInput(e) {
- var target = e.target;
- var name = e.type === "textarea" ? "innerHTML" : "value";
- target[name] = target._lastValue;
- }
- function preventUserClick(e) {
- e.preventDefault();
- }
- function preventUserChange(e) {
- var target = e.target,
- value = target._lastValue,
- options$$1 = target.options;
- if (target.multiple) {
- updateOptionsMore(options$$1, options$$1.length, value);
- } else {
- updateOptionsOne(options$$1, options$$1.length, value);
- }
- }
- function postUpdateSelectedOptions(vnode, target) {
- var props = vnode.props,
- multiple = !!props.multiple;
- target._lastValue = typeNumber(props.value) > 1 ? props.value : typeNumber(props.defaultValue) > 1 ? props.defaultValue : multiple ? [] : "";
- preventUserChange({
- target: target
- });
- }
- function updateOptionsOne(options$$1, n, propValue) {
- var stringValues = {};
- for (var i = 0; i < n; i++) {
- var option = options$$1[i];
- var value = option.duplexValue;
- if (value === propValue) {
- //精确匹配
- return setOptionSelected(option, true);
- }
- stringValues[value] = option;
- }
- var match = stringValues[propValue];
- if (match) {
- //字符串模糊匹配
- return setOptionSelected(match, true);
- }
- if (n) {
- //选中第一个
- setOptionSelected(options$$1[0], true);
- }
- }
- function updateOptionsMore(options$$1, n, propValue) {
- var selectedValue = {};
- try {
- for (var i = 0; i < propValue.length; i++) {
- selectedValue["&" + propValue[i]] = true;
- }
- } catch (e) {
- /* istanbul ignore next */
- console.warn('<select multiple="true"> 的value应该对应一个字符串数组'); // eslint-disable-line
- }
- for (var _i = 0; _i < n; _i++) {
- var option = options$$1[_i];
- var value = option.duplexValue;
- var selected = selectedValue.hasOwnProperty("&" + value);
- setOptionSelected(option, selected);
- }
- }
- function setOptionSelected(dom, selected) {
- dom.selected = selected;
- }
- var mountOrder = 1;
- function alwaysNull() {
- return null;
- }
- function Updater(instance, vnode) {
- vnode._instance = instance;
- instance.updater = this;
- this._mountOrder = mountOrder++;
- this._instance = instance;
- this._pendingCallbacks = [];
- // this._openRef = false;
- this._didHook = noop;
- this._pendingStates = [];
- this._lifeStage = 0; //判断生命周期
- //update总是保存最新的数据,如state, props, context, parentContext, vparent
- this.vnode = vnode;
- // this._hydrating = true 表示组件正在根据虚拟DOM合成真实DOM
- // this._renderInNextCycle = true 表示组件需要在下一周期重新渲染
- // this._forceUpdate = true 表示会无视shouldComponentUpdate的结果
- if (instance.__isStateless) {
- this.mergeStates = alwaysNull;
- }
- }
- var cbMap = {
- 1: "componentDidMount",
- 2: "componentDidUpdate"
- };
- Updater.prototype = {
- mergeStates: function mergeStates() {
- var instance = this._instance,
- pendings = this._pendingStates,
- state = instance.state,
- n = pendings.length;
- if (n === 0) {
- return state;
- }
- var nextState = extend({}, state); //每次都返回新的state
- for (var i = 0; i < n; i++) {
- var pending = pendings[i];
- if (pending && pending.call) {
- pending = pending.call(instance, nextState, this.props);
- }
- extend(nextState, pending);
- }
- pendings.length = 0;
- return nextState;
- },
- _ref: function _ref() {
- var vnode = this.vnode;
- if (vnode.ref && this._openRef) {
- var inst = this._instance;
- Refs.fireRef(vnode, inst.__isStateless ? null : inst);
- this._openRef = false;
- }
- },
- componentDidCallback: function componentDidCallback() {
- if (this._lifeStage > 0) {
- var instance = this._instance;
- var userHook = instance[cbMap[this._lifeStage]];
- this._lifeStage = -1;
- userHook && userHook.apply(instance, this.oldDatas);
- this.oldDatas = emptyArray;
- if (this._lifeStage == 1) {
- options.afterMount(instance);
- } else {
- options.afterUpdate(instance);
- }
- this._hydrating = false; // 见setStateImpl
- }
- },
- renderComponent: function renderComponent(cb) {
- var vnode = this.vnode,
- parentContext = this.parentContext,
- instance = this._instance;
- //调整全局的 CurrentOwner.cur
- var lastOwn = Refs.currentOwner,
- rendered = void 0;
- Refs.currentOwner = instance;
- try {
- if (this.willReceive === false) {
- rendered = this.rendered;
- delete this.willReceive;
- } else {
- rendered = instance.render();
- }
- } finally {
- Refs.currentOwner = lastOwn;
- }
- //组件只能返回组件或null
- if (rendered === null || rendered === false) {
- rendered = { type: "#comment", text: "empty", vtype: 0 };
- } else if (!rendered || !rendered.type) {
- //true, undefined, array, {}
- throw new Error("@" + vnode.type.name + "#render:You may have returned undefined, an array or some other invalid object");
- }
- var childContext = rendered.vtype ? getChildContext(instance, parentContext) : parentContext;
- var dom = cb(rendered, this.vparent, childContext);
- if (rendered._hostNode) {
- this.rendered = rendered;
- }
- if (!dom) {
- throw ["必须返回节点", rendered];
- }
- var u = this;
- do {
- u.vnode._hostNode = u._hostNode = dom;
- } while (u = u.parentUpdater);
- return dom;
- }
- };
- function instantiateComponent(type, vnode, props, context) {
- var isStateless = vnode.vtype === 4;
- var instance = isStateless ? {
- refs: {},
- render: function render() {
- return type(this.props, this.context);
- }
- } : new type(props, context);
- var updater = new Updater(instance, vnode, props, context);
- //props, context是不可变的
- instance.props = updater.props = props;
- instance.context = updater.context = context;
- instance.constructor = type;
- updater.displayName = type.displayName || type.name;
- if (isStateless) {
- var lastOwn = Refs.currentOwner;
- Refs.currentOwner = instance;
- try {
- var mixin = instance.render();
- } finally {
- Refs.currentOwner = lastOwn;
- }
- if (mixin && mixin.render) {
- //支持module pattern component
- extend(instance, mixin);
- } else {
- instance.__isStateless = true;
- updater.rendered = mixin;
- updater.willReceive = false;
- }
- }
- return instance;
- }
- function drainQueue(queue) {
- options.beforePatch();
- //先执行所有元素虚拟DOMrefs方法(从上到下)
- Refs.clearElementRefs();
- var needSort = [],
- unique = {},
- updater = void 0;
- while (updater = queue.shift()) {
- //queue可能中途加入新元素, 因此不能直接使用queue.forEach(fn)
- if (updater._disposed) {
- continue;
- }
- if (!unique[updater._mountOrder]) {
- unique[updater._mountOrder] = 1;
- needSort.push(updater);
- }
- Refs.clearElementRefs();
- updater._didUpdate = updater._lifeStage === 2;
- updater.componentDidCallback(); //执行所有mount/update钩子(从下到上)
- // updater._lifeStage = 1;
- // updater._hydrating = false;
- if (!updater._renderInNextCycle) {
- updater._didUpdate = false;
- }
- updater._ref(); //执行组件虚拟DOM的ref
- //如果组件在componentDidMount中调用setState
- if (updater._renderInNextCycle) {
- options.patchComponent(updater);
- }
- }
- //再执行所有setState/forceUpdate回调,根据从下到上的顺序执行
- needSort.sort(mountSorter).forEach(function (updater) {
- clearArray(updater._pendingCallbacks).forEach(function (fn) {
- fn.call(updater._instance);
- });
- });
- options.afterPatch();
- }
- var dirtyComponents = options.dirtyComponents;
- function mountSorter(u1, u2) {
- //按文档顺序执行
- return u1._mountOrder - u2._mountOrder;
- }
- options.flushUpdaters = function (queue) {
- if (!queue) {
- var last = dirtyComponents.last;
- if (!last) {
- return;
- }
- queue = clearArray(dirtyComponents);
- dirtyComponents.last = null;
- if (queue.length) {
- options.queue = queue;
- queue.last = last;
- queue.sort(mountSorter);
- } else {
- options.queue = last;
- }
- }
- drainQueue(queue);
- };
- options.enqueueUpdater = function (updater) {
- if (dirtyComponents.indexOf(updater) == -1) {
- dirtyComponents.push(updater);
- }
- };
- //[Top API] React.isValidElement
- function isValidElement(vnode) {
- return vnode && vnode.vtype;
- }
- //[Top API] ReactDOM.render
- function render(vnode, container, callback) {
- return renderByAnu(vnode, container, callback);
- }
- //[Top API] ReactDOM.unstable_renderSubtreeIntoContainer
- function unstable_renderSubtreeIntoContainer(lastVnode, nextVnode, container, callback) {
- deprecatedWarn("unstable_renderSubtreeIntoContainer");
- var parentContext = lastVnode && lastVnode.context || {};
- return renderByAnu(nextVnode, container, callback, parentContext);
- }
- //[Top API] ReactDOM.unmountComponentAtNode
- function unmountComponentAtNode(container) {
- var lastVnode = container.__component;
- if (lastVnode) {
- disposeVnode(lastVnode);
- emptyElement(container);
- container.__component = null;
- }
- }
- //[Top API] ReactDOM.findDOMNode
- function findDOMNode(ref) {
- if (ref == null) {
- return null;
- }
- if (ref.nodeType === 1) {
- return ref;
- }
- return ref.updater ? ref.updater._hostNode : ref._hostNode || null;
- }
- //[Top API] ReactDOM.createPortal
- function createPortal(vchildren, container) {
- var parentVnode = getVParent(container);
- parentVnode.vchildren = container.vchildren || emptyArray;
- diffChildren(getVParent(container), vchildren, container, {});
- parentVnode.vchildren = vchildren;
- return null;
- }
- // 用于辅助XML元素的生成(svg, math),
- // 它们需要根据父节点的tagName与namespaceURI,知道自己是存在什么文档中
- function getVParent(container) {
- return {
- type: container.nodeName,
- namespaceURI: container.namespaceURI
- };
- }
- // ReactDOM.render的内部实现
- function renderByAnu(vnode, container, callback) {
- var context = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
- if (!isValidElement(vnode)) {
- throw "ReactDOM.render\u7684\u7B2C\u4E00\u4E2A\u53C2\u6570\u9519\u8BEF"; // eslint-disable-line
- }
- if (!(container && container.getElementsByTagName)) {
- throw "ReactDOM.render\u7684\u7B2C\u4E8C\u4E2A\u53C2\u6570\u9519\u8BEF"; // eslint-disable-line
- }
- var rootNode = void 0,
- lastVnode = container.__component;
- if (lastVnode) {
- rootNode = alignVnode(lastVnode, vnode, getVParent(container), context);
- } else {
- //如果是后端渲染生成,它的孩子中存在一个拥有data-reactroot属性的元素节点
- rootNode = genVnodes(container, vnode, context);
- }
- if (rootNode.setAttribute) {
- rootNode.setAttribute("data-reactroot", "");
- }
- var instance = vnode._instance;
- container.__component = vnode;
- drainQueue(options.queue);
- // drainQueue(updateQueue);
- Refs.currentOwner = null; //防止干扰
- var ret = instance || rootNode;
- if (callback) {
- callback.call(ret); //坑
- }
- //组件返回组件实例,而普通虚拟DOM 返回元素节点
- return ret;
- }
- var toArray = Array.from || function (a) {
- var ret = [];
- for (var i = 0, n = a.length; i < n; i++) {
- ret[i] = a[i];
- }
- return ret;
- };
- function genVnodes(container, vnode, context) {
- var nodes = toArray(container.childNodes || emptyArray);
- var lastNode = null;
- for (var i = 0, el; el = nodes[i++];) {
- if (el.getAttribute && el.getAttribute("data-reactroot") !== null) {
- lastNode = el;
- } else {
- container.removeChild(el);
- }
- }
- return container.appendChild(mountVnode(lastNode, vnode, getVParent(container), context));
- }
- var patchStrategy = {
- 0: mountText,
- 1: mountElement,
- 2: mountComponent,
- 4: mountComponent,
- 10: updateText,
- 11: updateElement,
- 12: updateComponent,
- 14: updateComponent
- };
- //mountVnode只是转换虚拟DOM为真实DOM,不做插入DOM树操作
- function mountVnode(lastNode, vnode) {
- return patchStrategy[vnode.vtype].apply(null, arguments);
- }
- function updateVnode(lastVnode) {
- return patchStrategy[lastVnode.vtype + 10].apply(null, arguments);
- }
- function mountText(lastNode, vnode) {
- if (!lastNode || lastNode.nodeName !== vnode.type) {
- lastNode = createElement$1(vnode);
- }
- return vnode._hostNode = lastNode;
- }
- function updateText(lastVnode, nextVnode) {
- var dom = lastVnode._hostNode;
- nextVnode._hostNode = dom;
- if (lastVnode.text !== nextVnode.text) {
- dom.nodeValue = nextVnode.text;
- }
- return dom;
- }
- function genMountElement(lastNode, vnode, vparent, type) {
- if (lastNode && toLowerCase(lastNode.nodeName) === type) {
- return lastNode;
- } else {
- var dom = createElement$1(vnode, vparent);
- if (lastNode) {
- while (lastNode.firstChild) {
- dom.appendChild(lastNode.firstChild);
- }
- }
- return dom;
- }
- }
- var formElements = {
- select: 1,
- textarea: 1,
- input: 1,
- option: 1
- };
- function mountElement(lastNode, vnode, vparent, context) {
- var type = vnode.type,
- props = vnode.props,
- _hasRef = vnode._hasRef;
- var dom = genMountElement(lastNode, vnode, vparent, type);
- vnode._hostNode = dom;
- var children = flattenChildren(vnode);
- var method = lastNode ? alignChildren : mountChildren;
- method(dom, children, vnode, context);
- // dom.vchildren = children;/** fatal 不再访问真实DOM */
- if (vnode.checkProps) {
- diffProps(dom, emptyObject, props, vnode);
- }
- if (formElements[type]) {
- processFormElement(vnode, dom, props);
- }
- if (_hasRef) {
- pendingRefs.push(vnode, dom);
- }
- return dom;
- }
- function updateElement(lastVnode, nextVnode, vparent, context) {
- var lastProps = lastVnode.props,
- dom = lastVnode._hostNode,
- checkProps = lastVnode.checkProps,
- type = lastVnode.type;
- var nextProps = nextVnode.props,
- nextCheckProps = nextVnode.checkProps;
- nextVnode._hostNode = dom;
- var vchildren = lastVnode.vchildren || emptyArray,
- newChildren = void 0;
- if (nextProps[innerHTML]) {
- vchildren.forEach(function (el) {
- disposeVnode(el);
- });
- vchildren.length = 0;
- } else {
- if (nextVnode === lastVnode) {
- //如果新旧节点一样,为了防止旧vchildren被重写,需要restore一下
- newChildren = vchildren.concat();
- } else {
- newChildren = flattenChildren(nextVnode);
- }
- if (lastProps[innerHTML]) {
- vchildren.length = 0;
- }
- diffChildren(lastVnode, newChildren, dom, context);
- nextVnode.vchildren = newChildren;
- }
- if (checkProps || nextCheckProps) {
- diffProps(dom, lastProps, nextProps, nextVnode);
- }
- if (formElements[type]) {
- processFormElement(nextVnode, dom, nextProps);
- }
- Refs.detachRef(lastVnode, nextVnode, dom);
- return dom;
- }
- //将虚拟DOM转换为真实DOM并插入父元素
- function mountChildren(parentNode, children, vparent, context) {
- for (var i = 0, n = children.length; i < n; i++) {
- var vnode = children[i];
- parentNode.appendChild(mountVnode(null, vnode, vparent, context));
- }
- }
- function alignChildren(parentNode, children, vparent, context) {
- var childNodes = parentNode.childNodes,
- insertPoint = childNodes[0] || null,
- j = 0,
- n = children.length;
- for (var i = 0; i < n; i++) {
- var vnode = children[i];
- var lastNode = childNodes[j];
- var dom = mountVnode(lastNode, vnode, vparent, context);
- if (dom === lastNode) {
- j++;
- }
- parentNode.insertBefore(dom, insertPoint);
- insertPoint = dom.nextSibling;
- }
- while (childNodes[n]) {
- parentNode.removeChild(childNodes[n]);
- }
- }
- function mountComponent(lastNode, vnode, vparent, parentContext, parentUpdater) {
- var type = vnode.type,
- props = vnode.props,
- ref = vnode.ref;
- var context = getContextByTypes(parentContext, type.contextTypes);
- var instance = instantiateComponent(type, vnode, props, context); //互相持有引用
- var updater = instance.updater;
- if (parentUpdater) {
- updater.parentUpdater = parentUpdater;
- }
- updater.vparent = vparent;
- updater.parentContext = parentContext;
- if (instance.componentWillMount) {
- instance.componentWillMount(); //这里可能执行了setState
- instance.state = updater.mergeStates();
- }
- updater._hydrating = true;
- var dom = updater.renderComponent(function (nextRendered, vparent, childContext) {
- return mountVnode(lastNode, nextRendered, vparent, childContext, updater //作为parentUpater往下传
- );
- });
- updater._openRef = !!ref;
- updater._lifeStage = 1;
- updater.oldDatas = emptyArray;
- options.queue.push(updater);
- return dom;
- }
- function updateComponent(lastVnode, nextVnode, vparent, parentContext) {
- var type = lastVnode.type,
- _hasRef = lastVnode._hasRef,
- instance = lastVnode._instance,
- _hostNode = lastVnode._hostNode;
- var nextContext = void 0,
- nextProps = nextVnode.props,
- updater = instance.updater;
- if (type.contextTypes) {
- nextContext = getContextByTypes(parentContext, type.contextTypes);
- } else {
- nextContext = instance.context; //没有定义contextTypes就沿用旧的
- }
- var willReceive = lastVnode !== nextVnode || updater.context !== nextContext;
- nextVnode._hostNode = _hostNode;
- nextVnode._instance = instance;
- updater.willReceive = willReceive;
- //如果context与props都没有改变,那么就不会触发组件的receive,render,update等一系列钩子
- //但还会继续向下比较
- if (willReceive && instance.componentWillReceiveProps) {
- updater._receiving = true;
- instance.componentWillReceiveProps(nextProps, nextContext);
- updater._receiving = false;
- }
- _hasRef && Refs.detachRef(lastVnode, nextVnode);
- updater._openRef = nextVnode.ref;
- //updater上总是保持新的数据
- updater.context = nextContext;
- updater.props = nextProps;
- updater.vparent = vparent;
- updater.parentContext = parentContext;
- // nextVnode._instance = instance; //不能放这里
- if (!willReceive) {
- return updater.renderComponent(function (nextRendered, vparent, childContext) {
- return alignVnode(updater.rendered, nextRendered, vparent, childContext);
- });
- }
- updater.vnode = nextVnode;
- patchComponent(updater);
- //子组件先执行
- options.queue.push(updater);
- return updater._hostNode;
- }
- function patchComponent(updater) {
- var instance = updater._instance,
- dom = updater._hostNode,
- nextContext = updater.context,
- nextProps = updater.props,
- vnode = updater.vnode;
- if (updater._lifeStage === 1) {
- return dom;
- }
- vnode._instance = instance; //放这里
- updater._renderInNextCycle = null;
- var nextState = updater.mergeStates();
- var shouldUpdate = true;
- if (!updater._forceUpdate && instance.shouldComponentUpdate && !instance.shouldComponentUpdate(nextProps, nextState, nextContext)) {
- shouldUpdate = false;
- } else if (instance.componentWillUpdate) {
- instance.componentWillUpdate(nextProps, nextState, nextContext);
- }
- var lastProps = instance.props,
- lastContext = instance.context,
- lastState = instance.state;
- updater._forceUpdate = false;
- instance.state = nextState; //既然setState了,无论shouldComponentUpdate结果如何,用户传给的state对象都会作用到组件上
- instance.context = nextContext;
- if (!shouldUpdate) {
- options.queue.push(updater);
- return dom;
- }
- instance.props = nextProps;
- updater._hydrating = true;
- var lastRendered = updater.rendered;
- dom = updater.renderComponent(function (nextRendered, vparent, childContext) {
- return alignVnode(lastRendered, nextRendered, vparent, childContext, updater);
- });
- updater._lifeStage = 2;
- updater.oldDatas = [lastProps, lastState, lastContext];
- options.queue.push(updater);
- return dom;
- }
- options.patchComponent = patchComponent;
- var fakeLastNode = {
- _disposed: true
- };
- function alignVnode(lastVnode, nextVnode, vparent, context, parentUpdater) {
- var dom = void 0;
- if (isSameNode(lastVnode, nextVnode)) {
- dom = updateVnode(lastVnode, nextVnode, vparent, context);
- } else {
- disposeVnode(lastVnode);
- var node = lastVnode._hostNode,
- parentNode = node.parentNode;
- dom = mountVnode(null, nextVnode, vparent, context, parentUpdater);
- parentNode.replaceChild(dom, node);
- }
- return dom;
- }
- function genkey(vnode) {
- return vnode.key ? "@" + vnode.key : vnode.type.name || vnode.type;
- }
- function diffChildren(parentVnode, nextChildren, parentNode, context) {
- var lastChildren = parentVnode.vchildren || emptyArray,
- //parentNode.vchildren,
- nextLength = nextChildren.length,
- insertPoint = parentNode.firstChild,
- lastLength = lastChildren.length;
- //optimize 1: 如果旧数组长度为零, 只进行添加
- if (!lastLength) {
- emptyElement(parentNode);
- return mountChildren(parentNode, nextChildren, parentVnode, context);
- }
- //optimize 2: 如果新数组长度为零, 只进行删除
- if (!nextLength) {
- return lastChildren.forEach(function (el) {
- removeElement(el._hostNode);
- disposeVnode(el);
- });
- }
- //optimize 3: 如果1vs1, 不用进入下面复杂的循环
- if (nextLength === lastLength && lastLength === 1) {
- if (insertPoint) {
- lastChildren[0]._hostNode = insertPoint;
- }
- return alignVnode(lastChildren[0], nextChildren[0], parentVnode, context);
- }
- var mergeChildren = [],
- //确保新旧数组都按原顺数排列
- fuzzyHits = {},
- i = 0,
- hit = void 0,
- oldDom = void 0,
- dom = void 0,
- nextChild = void 0;
- lastChildren.forEach(function (lastChild) {
- hit = genkey(lastChild);
- mergeChildren.push(lastChild);
- var hits = fuzzyHits[hit];
- if (hits) {
- hits.push(lastChild);
- } else {
- fuzzyHits[hit] = [lastChild];
- }
- });
- while (i < nextLength) {
- nextChild = nextChildren[i];
- nextChild._new = true;
- hit = genkey(nextChild);
- if (fuzzyHits[hit] && fuzzyHits[hit].length) {
- var oldChild = fuzzyHits[hit].shift();
- // 如果命中旧节点,置空旧节点,并在新位置放入旧节点(向后移动)
- var lastIndex = mergeChildren.indexOf(oldChild);
- if (lastIndex !== -1) {
- mergeChildren[lastIndex] = fakeLastNode;
- // mergeChildren.splice(lastIndex, 1);
- }
- nextChild._new = oldChild;
- }
- mergeChildren.splice(i, 0, nextChild);
- i++;
- }
- for (var j = 0, n = mergeChildren.length; j < n; j++) {
- var _nextChild = mergeChildren[j];
- if (_nextChild._new) {
- var lastChild = _nextChild._new;
- delete _nextChild._new;
- if (dom) {
- insertPoint = dom.nextSibling;
- }
- if (lastChild === true) {
- //新节点有两种情况,命中位置更后方的旧节点或就地创建实例化
- dom = mountVnode(null, _nextChild, parentVnode, context);
- insertElement(parentNode, dom, insertPoint);
- } else {
- oldDom = lastChild._hostNode;
- if (oldDom !== insertPoint) {
- insertElement(parentNode, oldDom, insertPoint);
- }
- dom = alignVnode(lastChild, _nextChild, parentVnode, context);
- }
- } else {
- if (_nextChild._hostNode) {
- removeElement(_nextChild._hostNode);
- disposeVnode(_nextChild);
- }
- }
- }
- }
- function isSameNode(a, b) {
- if (a.type === b.type && a.key === b.key) {
- return true;
- }
- }
- var React = {
- version: "1.1.4",
- render: render,
- options: options,
- PropTypes: PropTypes,
- Children: Children, //为了react-redux
- createPortal: createPortal,
- Component: Component,
- eventSystem: eventSystem,
- findDOMNode: findDOMNode,
- createClass: createClass,
- createElement: createElement,
- cloneElement: cloneElement,
- PureComponent: PureComponent,
- isValidElement: isValidElement,
- unmountComponentAtNode: unmountComponentAtNode,
- unstable_renderSubtreeIntoContainer: unstable_renderSubtreeIntoContainer,
- createFactory: function createFactory(type) {
- console.error("createFactory is deprecated"); // eslint-disable-line
- var factory = createElement.bind(null, type);
- factory.type = type;
- return factory;
- }
- };
- win.React = win.ReactDOM = React;
- return React;
- })));
|