@viewfly/core 1.0.0-alpha.2 → 1.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -161,6 +161,40 @@ var InjectFlags;
161
161
  class Injector {
162
162
  }
163
163
 
164
+ /**
165
+ * 构造函数参数装饰器,用于改变注入 token
166
+ */
167
+ const Inject = function InjectDecorator(token) {
168
+ if (this instanceof Inject) {
169
+ this.token = token;
170
+ }
171
+ else {
172
+ return makeParamDecorator(Inject, new Inject(token));
173
+ }
174
+ };
175
+ const Self = function SelfDecorator() {
176
+ if (!(this instanceof Self)) {
177
+ return makeParamDecorator(Self, new Self());
178
+ }
179
+ };
180
+ const SkipSelf = function SkipSelfDecorator() {
181
+ if (!(this instanceof SkipSelf)) {
182
+ return makeParamDecorator(SkipSelf, new SkipSelf());
183
+ }
184
+ };
185
+ const Optional = function OptionalDecorator() {
186
+ if (!(this instanceof Optional)) {
187
+ return makeParamDecorator(Optional, new Optional());
188
+ }
189
+ };
190
+ const Prop = function PropDecorator(token, notFoundValue, flags) {
191
+ if (!(this instanceof Prop)) {
192
+ return makePropertyDecorator(Prop, token, function (instance, propertyName, token, injector) {
193
+ instance[propertyName] = injector.get(token instanceof ForwardRef ? token.getRef() : token, notFoundValue, flags);
194
+ });
195
+ }
196
+ };
197
+
164
198
  function stringify(token) {
165
199
  if (typeof token === 'string') {
166
200
  return token;
@@ -200,12 +234,12 @@ const THROW_IF_NOT_FOUND = {
200
234
  const nullInjectorErrorFn = (token) => {
201
235
  return makeError('NullInjector')(`No provide for \`${stringify(token)}\`!`);
202
236
  };
203
- class NullInjector extends Injector {
237
+ class NullInjector {
204
238
  constructor() {
205
- super(...arguments);
206
239
  this.parentInjector = null;
207
240
  }
208
- get(token, flag, notFoundValue = THROW_IF_NOT_FOUND) {
241
+ /* eslint-disable-next-line */
242
+ get(token, notFoundValue = THROW_IF_NOT_FOUND, _) {
209
243
  if (notFoundValue === THROW_IF_NOT_FOUND) {
210
244
  throw nullInjectorErrorFn(token);
211
245
  }
@@ -213,40 +247,6 @@ class NullInjector extends Injector {
213
247
  }
214
248
  }
215
249
 
216
- /**
217
- * 构造函数参数装饰器,用于改变注入 token
218
- */
219
- const Inject = function InjectDecorator(token) {
220
- if (this instanceof Inject) {
221
- this.token = token;
222
- }
223
- else {
224
- return makeParamDecorator(Inject, new Inject(token));
225
- }
226
- };
227
- const Self = function SelfDecorator() {
228
- if (!(this instanceof Self)) {
229
- return makeParamDecorator(Self, new Self());
230
- }
231
- };
232
- const SkipSelf = function SkipSelfDecorator() {
233
- if (!(this instanceof SkipSelf)) {
234
- return makeParamDecorator(SkipSelf, new SkipSelf());
235
- }
236
- };
237
- const Optional = function OptionalDecorator() {
238
- if (!(this instanceof Optional)) {
239
- return makeParamDecorator(Optional, new Optional());
240
- }
241
- };
242
- const Prop = function PropDecorator(token, flags, notFoundValue = THROW_IF_NOT_FOUND) {
243
- if (!(this instanceof Prop)) {
244
- return makePropertyDecorator(Prop, token, function (instance, propertyName, token, injector) {
245
- instance[propertyName] = injector.get(token instanceof ForwardRef ? token.getRef() : token, flags, notFoundValue);
246
- });
247
- }
248
- };
249
-
250
250
  /**
251
251
  * 标准化 provide,并返回统一数据结构
252
252
  * @param provider
@@ -410,11 +410,9 @@ const provideScopeError = (token) => {
410
410
  /**
411
411
  * 反射注入器
412
412
  */
413
- class ReflectiveInjector extends Injector {
413
+ class ReflectiveInjector {
414
414
  constructor(parentInjector, staticProviders, scope) {
415
- super();
416
415
  this.parentInjector = parentInjector;
417
- this.staticProviders = staticProviders;
418
416
  this.scope = scope;
419
417
  this.recordValues = new Map();
420
418
  this.normalizedProviders = staticProviders.map(provide => {
@@ -424,15 +422,15 @@ class ReflectiveInjector extends Injector {
424
422
  /**
425
423
  * 用于获取当前注入器上下文内的实例、对象或数据
426
424
  * @param token 访问 token
427
- * @param flags 查询规则
428
425
  * @param notFoundValue 如未查找到的返回值
426
+ * @param flags 查询规则
429
427
  */
430
- get(token, flags = InjectFlags.Default, notFoundValue = THROW_IF_NOT_FOUND) {
428
+ get(token, notFoundValue = THROW_IF_NOT_FOUND, flags) {
431
429
  var _a;
432
430
  flags = flags || InjectFlags.Default;
433
431
  if (flags === InjectFlags.SkipSelf) {
434
432
  if (this.parentInjector) {
435
- return this.parentInjector.get(token, InjectFlags.Default, notFoundValue);
433
+ return this.parentInjector.get(token, notFoundValue);
436
434
  }
437
435
  if (notFoundValue !== THROW_IF_NOT_FOUND) {
438
436
  return notFoundValue;
@@ -476,9 +474,12 @@ class ReflectiveInjector extends Injector {
476
474
  return notFoundValue;
477
475
  }
478
476
  if (this.parentInjector) {
479
- return this.parentInjector.get(token, flags === InjectFlags.Optional ? InjectFlags.Optional : InjectFlags.Default, notFoundValue);
477
+ return this.parentInjector.get(token, notFoundValue, flags === InjectFlags.Optional ? InjectFlags.Optional : InjectFlags.Default);
480
478
  }
481
479
  if (notFoundValue === THROW_IF_NOT_FOUND) {
480
+ // if (flags === InjectFlags.Optional) {
481
+ // return null as U
482
+ // }
482
483
  throw reflectiveInjectorErrorFn(token);
483
484
  }
484
485
  return notFoundValue;
@@ -508,11 +509,11 @@ class ReflectiveInjector extends Injector {
508
509
  const tryValue = {};
509
510
  const injectToken = dep.injectKey instanceof ForwardRef ? dep.injectKey.getRef() : dep.injectKey;
510
511
  if (dep.visibility instanceof Self) {
511
- reflectiveValue = this.get(injectToken, InjectFlags.Self, tryValue);
512
+ reflectiveValue = this.get(injectToken, tryValue, InjectFlags.Self);
512
513
  }
513
514
  else if (dep.visibility instanceof SkipSelf) {
514
515
  if (this.parentInjector) {
515
- reflectiveValue = this.parentInjector.get(injectToken, InjectFlags.Default, tryValue);
516
+ reflectiveValue = this.parentInjector.get(injectToken, tryValue);
516
517
  }
517
518
  else {
518
519
  if (dep.optional) {
@@ -525,7 +526,7 @@ class ReflectiveInjector extends Injector {
525
526
  }
526
527
  }
527
528
  else {
528
- reflectiveValue = this.get(injectToken, InjectFlags.Default, tryValue);
529
+ reflectiveValue = this.get(injectToken, tryValue);
529
530
  }
530
531
  if (reflectiveValue === tryValue) {
531
532
  if (dep.optional) {
@@ -587,13 +588,13 @@ function getArrayChanges(left, right) {
587
588
  return changes;
588
589
  }
589
590
  function classToString(config) {
590
- if (!config) {
591
- return '';
592
- }
593
591
  if (typeof config === 'string') {
594
592
  return config;
595
593
  }
596
- else if (Array.isArray(config)) {
594
+ if (!config) {
595
+ return '';
596
+ }
597
+ if (Array.isArray(config)) {
597
598
  const classes = [];
598
599
  for (const i of config) {
599
600
  const v = classToString(i);
@@ -603,7 +604,7 @@ function classToString(config) {
603
604
  }
604
605
  return classes.join(' ');
605
606
  }
606
- else if (typeof config === 'object') {
607
+ if (typeof config === 'object') {
607
608
  if (config.toString !== Object.prototype.toString && !config.toString.toString().includes('[native code]')) {
608
609
  return config.toString();
609
610
  }
@@ -630,6 +631,9 @@ function styleToObject(style) {
630
631
  });
631
632
  return obj;
632
633
  }
634
+ const TextAtomType = Symbol('Text');
635
+ const ElementAtomType = Symbol('Element');
636
+ const ComponentAtomType = Symbol('Component');
633
637
 
634
638
  const componentSetupStack = [];
635
639
  const signalDepsStack = [];
@@ -736,30 +740,29 @@ class Component extends ReflectiveInjector {
736
740
  portalHost: this.instance.$portalHost
737
741
  };
738
742
  }
739
- update(newProps, forceUpdate = false) {
743
+ update(newProps) {
740
744
  const oldProps = this.props;
741
- const { add, remove, replace } = getObjectChanges(newProps, this.props);
742
- if (add.length || remove.length || replace.length) {
743
- this.invokePropsChangedHooks(newProps);
744
- }
745
- else if (!this.dirty) {
746
- return this.template;
747
- }
748
- const newRefs = toRefs(newProps.ref);
749
- if (this.refs) {
750
- for (const oldRef of this.refs) {
751
- if (!newRefs.includes(oldRef)) {
752
- oldRef.unBind(this.instance);
745
+ if (newProps !== oldProps) {
746
+ const { add, remove, replace } = getObjectChanges(newProps, oldProps);
747
+ if (add.length || remove.length || replace.length) {
748
+ this.invokePropsChangedHooks(newProps);
749
+ }
750
+ const newRefs = toRefs(newProps.ref);
751
+ if (this.refs) {
752
+ for (const oldRef of this.refs) {
753
+ if (!newRefs.includes(oldRef)) {
754
+ oldRef.unBind(this.instance);
755
+ }
753
756
  }
754
757
  }
758
+ for (const newRef of newRefs) {
759
+ newRef.bind(this.instance);
760
+ }
761
+ if (newRefs.length) {
762
+ this.refs = newRefs;
763
+ }
755
764
  }
756
- for (const newRef of newRefs) {
757
- newRef.bind(this.instance);
758
- }
759
- if (newRefs.length) {
760
- this.refs = newRefs;
761
- }
762
- if (!forceUpdate && typeof this.instance.$useMemo === 'function') {
765
+ if (typeof this.instance.$useMemo === 'function') {
763
766
  if (this.instance.$useMemo(newProps, oldProps)) {
764
767
  return this.template;
765
768
  }
@@ -843,7 +846,12 @@ class Component extends ReflectiveInjector {
843
846
  }
844
847
  }
845
848
  if (unmountedCallbacks.length) {
846
- this.unmountedCallbacks = unmountedCallbacks;
849
+ if (this.unmountedCallbacks) {
850
+ this.unmountedCallbacks.push(...unmountedCallbacks);
851
+ }
852
+ else {
853
+ this.unmountedCallbacks = unmountedCallbacks;
854
+ }
847
855
  }
848
856
  this.mountCallbacks = null;
849
857
  }
@@ -1232,9 +1240,9 @@ function withAnnotation(annotation, componentSetup) {
1232
1240
  /**
1233
1241
  * 通过组件上下文获取 IoC 容器内数据的勾子方法
1234
1242
  */
1235
- function inject(token, flags = InjectFlags.Default, notFoundValue = THROW_IF_NOT_FOUND) {
1243
+ function inject(token, notFoundValue = THROW_IF_NOT_FOUND, flags) {
1236
1244
  const component = getSetupContext();
1237
- return component.get(token, flags, notFoundValue);
1245
+ return component.get(token, notFoundValue, flags);
1238
1246
  }
1239
1247
  /**
1240
1248
  * 获取当前组件实例
@@ -1272,14 +1280,17 @@ function withMemo(canUseMemo, render) {
1272
1280
  };
1273
1281
  }
1274
1282
 
1275
- const listenerReg = /^on(?=[A-Z])/;
1283
+ const componentViewCache = new WeakMap();
1284
+ const listenerReg = /^on[A-Z]/;
1276
1285
  function createRenderer(component, nativeRenderer) {
1277
1286
  let isInit = true;
1278
1287
  return function render(host) {
1279
1288
  if (isInit) {
1280
1289
  isInit = false;
1281
1290
  const atom = {
1282
- type: 'component',
1291
+ type: ComponentAtomType,
1292
+ index: 0,
1293
+ nodeType: component.type,
1283
1294
  jsxNode: component,
1284
1295
  sibling: null,
1285
1296
  child: null,
@@ -1299,41 +1310,28 @@ function createRenderer(component, nativeRenderer) {
1299
1310
  }
1300
1311
  function buildView(nativeRenderer, parentComponent, atom, context) {
1301
1312
  const { jsxNode, type } = atom;
1302
- if (type === 'component') {
1313
+ if (type === ComponentAtomType) {
1303
1314
  const component = new Component(parentComponent, jsxNode.type, jsxNode.props, jsxNode.key);
1304
1315
  atom.jsxNode = component;
1305
1316
  componentRender(nativeRenderer, component, atom, context);
1306
1317
  }
1318
+ else if (type === ElementAtomType) {
1319
+ createElement(nativeRenderer, atom, parentComponent, context);
1320
+ }
1307
1321
  else {
1308
- let nativeNode;
1309
- let applyRefs = null;
1310
- if (type === 'element') {
1311
- const { nativeNode: n, applyRefs: a } = createElement(nativeRenderer, jsxNode, atom.isSvg);
1312
- nativeNode = n;
1313
- applyRefs = a;
1314
- }
1315
- else {
1316
- nativeNode = createTextNode(nativeRenderer, jsxNode, atom.isSvg);
1317
- }
1318
- atom.nativeNode = nativeNode;
1319
- insertNode(nativeRenderer, atom, context);
1320
- if (type === 'element') {
1321
- const childContext = {
1322
- isParent: true,
1323
- host: nativeNode,
1324
- rootHost: context.rootHost
1325
- };
1326
- let child = atom.child;
1327
- while (child) {
1328
- buildView(nativeRenderer, parentComponent, child, childContext);
1329
- child = child.sibling;
1330
- }
1331
- }
1332
- context.host = nativeNode;
1333
- context.isParent = false;
1334
- if (applyRefs) {
1335
- applyRefs();
1336
- }
1322
+ createTextNode(nativeRenderer, atom, context);
1323
+ }
1324
+ }
1325
+ function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1326
+ const childContext = {
1327
+ isParent: true,
1328
+ host: atom.nativeNode,
1329
+ rootHost: context.rootHost
1330
+ };
1331
+ let child = atom.child;
1332
+ while (child) {
1333
+ buildView(nativeRenderer, parentComponent, child, childContext);
1334
+ child = child.sibling;
1337
1335
  }
1338
1336
  }
1339
1337
  function updateView(nativeRenderer, component) {
@@ -1349,115 +1347,77 @@ function updateView(nativeRenderer, component) {
1349
1347
  }
1350
1348
  }
1351
1349
  function applyChanges(nativeRenderer, component) {
1352
- const { atom, host, isParent, rootHost } = component.$$view;
1350
+ const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1353
1351
  const diffAtom = atom.child;
1354
- const template = component.update(component.props, true);
1352
+ const template = component.update(component.props);
1355
1353
  atom.child = createChildChain(template, atom.isSvg);
1356
1354
  const context = {
1357
1355
  host,
1358
1356
  isParent,
1359
1357
  rootHost
1360
1358
  };
1361
- diff(nativeRenderer, component, atom.child, diffAtom, context, 0, 0);
1359
+ diff(nativeRenderer, component, atom.child, diffAtom, context, false);
1362
1360
  const next = atom.sibling;
1363
1361
  if (next && next.jsxNode instanceof Component) {
1364
- next.jsxNode.$$view.host = context.host;
1365
- next.jsxNode.$$view.isParent = context.isParent;
1366
- }
1367
- }
1368
- function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, expectIndex, index) {
1369
- let prevDiffAtom = null;
1370
- let firstDiffAtomIndexed = null;
1371
- if (oldAtom) {
1372
- prevDiffAtom = {
1373
- index,
1374
- atom: oldAtom,
1375
- prev: null
1376
- };
1377
- index++;
1378
- firstDiffAtomIndexed = prevDiffAtom;
1379
- oldAtom = oldAtom.sibling;
1380
- while (oldAtom) {
1381
- const diffAtom = {
1382
- index,
1383
- atom: oldAtom,
1384
- prev: prevDiffAtom
1385
- };
1386
- prevDiffAtom.next = diffAtom;
1387
- prevDiffAtom = diffAtom;
1388
- oldAtom = oldAtom.sibling;
1389
- index++;
1390
- }
1362
+ const view = componentViewCache.get(next.jsxNode);
1363
+ view.host = context.host;
1364
+ view.isParent = context.isParent;
1391
1365
  }
1366
+ }
1367
+ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1392
1368
  const commits = [];
1393
1369
  function changeOffset() {
1394
1370
  offset++;
1395
1371
  }
1396
1372
  while (newAtom) {
1397
- firstDiffAtomIndexed = createChanges(newAtom, expectIndex, firstDiffAtomIndexed, nativeRenderer, commits, context, parentComponent, changeOffset);
1373
+ oldAtom = createChanges(newAtom, oldAtom, nativeRenderer, commits, context, parentComponent, changeOffset);
1398
1374
  newAtom = newAtom.sibling;
1399
- expectIndex++;
1400
1375
  }
1401
- let dirtyDiffAtom = firstDiffAtomIndexed;
1376
+ let dirtyDiffAtom = oldAtom;
1402
1377
  while (dirtyDiffAtom) {
1403
- cleanView(nativeRenderer, dirtyDiffAtom.atom, false);
1404
- dirtyDiffAtom = dirtyDiffAtom.next;
1378
+ cleanView(nativeRenderer, dirtyDiffAtom, true);
1379
+ dirtyDiffAtom = dirtyDiffAtom.sibling;
1405
1380
  }
1406
1381
  let offset = 0;
1407
1382
  for (let i = 0; i < commits.length; i++) {
1408
1383
  const commit = commits[i];
1409
- while (firstDiffAtomIndexed) {
1410
- if (firstDiffAtomIndexed.index <= i) {
1384
+ while (oldAtom) {
1385
+ if (oldAtom.index <= i) {
1411
1386
  offset--;
1412
- firstDiffAtomIndexed = firstDiffAtomIndexed.next;
1387
+ oldAtom = oldAtom.sibling;
1413
1388
  continue;
1414
1389
  }
1415
1390
  break;
1416
1391
  }
1417
- commit(offset);
1392
+ commit(offset, needMove);
1418
1393
  }
1419
1394
  }
1420
- function createChanges(newAtom, expectIndex, diffAtomIndexed, nativeRenderer, commits, context, parentComponent, effect) {
1421
- const startDiffAtom = diffAtomIndexed;
1422
- const { jsxNode: newJsxNode, type } = newAtom;
1423
- const key = newJsxNode.key;
1424
- while (diffAtomIndexed) {
1425
- const { atom: diffAtom, index: diffIndex } = diffAtomIndexed;
1426
- if (type === diffAtom.type) {
1395
+ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, parentComponent, effect) {
1396
+ const startDiffAtom = oldAtom;
1397
+ let prev = null;
1398
+ while (oldAtom) {
1399
+ const newAtomType = newAtom.type;
1400
+ if (oldAtom.type === newAtomType && oldAtom.nodeType === newAtom.nodeType && oldAtom.key === newAtom.key) {
1427
1401
  let commit;
1428
- if (type === 'text') {
1429
- commit = updateText(newAtom, diffAtom, nativeRenderer, context);
1402
+ if (newAtomType === TextAtomType) {
1403
+ commit = updateText(newAtom, oldAtom, nativeRenderer, context);
1404
+ }
1405
+ else if (newAtomType === ComponentAtomType) {
1406
+ commit = updateComponent(newAtom, oldAtom, nativeRenderer, context);
1430
1407
  }
1431
1408
  else {
1432
- const { key: diffKey, type: diffType } = diffAtom.jsxNode;
1433
- if (diffKey !== key || newJsxNode.type !== diffType) {
1434
- diffAtomIndexed = diffAtomIndexed.next;
1435
- continue;
1436
- }
1437
- if (type === 'component') {
1438
- commit = updateComponent(newAtom, diffAtom, expectIndex, diffIndex, nativeRenderer, context);
1439
- }
1440
- else {
1441
- commit = updateElement(newAtom, diffAtom, expectIndex, diffIndex, nativeRenderer, context, parentComponent);
1442
- }
1409
+ commit = updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent);
1443
1410
  }
1444
1411
  commits.push(commit);
1445
- const next = diffAtomIndexed.next;
1446
- const prev = diffAtomIndexed.prev;
1412
+ const next = oldAtom.sibling;
1447
1413
  if (!prev) {
1448
- diffAtomIndexed = next;
1449
- if (diffAtomIndexed) {
1450
- diffAtomIndexed.prev = null;
1451
- }
1452
- return diffAtomIndexed;
1453
- }
1454
- prev.next = next;
1455
- if (next) {
1456
- next.prev = prev;
1414
+ return next;
1457
1415
  }
1416
+ prev.sibling = next;
1458
1417
  return startDiffAtom;
1459
1418
  }
1460
- diffAtomIndexed = diffAtomIndexed.next;
1419
+ prev = oldAtom;
1420
+ oldAtom = oldAtom.sibling;
1461
1421
  }
1462
1422
  commits.push(createNewView(newAtom, nativeRenderer, context, parentComponent, effect));
1463
1423
  return startDiffAtom;
@@ -1469,77 +1429,60 @@ function createNewView(start, nativeRenderer, context, parentComponent, effect)
1469
1429
  };
1470
1430
  }
1471
1431
  function updateText(newAtom, oldAtom, nativeRenderer, context) {
1472
- return function () {
1432
+ return function (offset, needMove) {
1473
1433
  const nativeNode = oldAtom.nativeNode;
1474
- if (newAtom.jsxNode !== oldAtom.jsxNode) {
1475
- nativeRenderer.syncTextContent(nativeNode, newAtom.jsxNode, newAtom.isSvg);
1476
- }
1477
1434
  newAtom.nativeNode = nativeNode;
1435
+ if (needMove || newAtom.index - offset !== oldAtom.index) {
1436
+ insertNode(nativeRenderer, newAtom, context);
1437
+ }
1478
1438
  context.host = nativeNode;
1479
1439
  context.isParent = false;
1480
1440
  };
1481
1441
  }
1482
- function updateElement(newAtom, oldAtom, expectIndex, oldIndex, nativeRenderer, context, parentComponent) {
1483
- return function (offset) {
1442
+ function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent) {
1443
+ return function (offset, needMove) {
1484
1444
  newAtom.nativeNode = oldAtom.nativeNode;
1485
- if (expectIndex - offset !== oldIndex) {
1445
+ if (needMove || newAtom.index - offset !== oldAtom.index) {
1486
1446
  insertNode(nativeRenderer, newAtom, context);
1487
1447
  }
1488
1448
  context.host = newAtom.nativeNode;
1489
1449
  context.isParent = false;
1490
- const applyRefs = updateNativeNodeProperties(nativeRenderer, newAtom.jsxNode, oldAtom.jsxNode, newAtom.nativeNode, newAtom.isSvg);
1491
- if (newAtom.child) {
1492
- diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, {
1493
- host: newAtom.nativeNode,
1494
- isParent: true,
1495
- rootHost: context.rootHost
1496
- }, 0, 0);
1497
- }
1498
- else if (oldAtom.child) {
1499
- let atom = oldAtom.child;
1500
- nativeRenderer.cleanChildren(oldAtom.nativeNode, oldAtom.isSvg);
1501
- while (atom) {
1502
- cleanView(nativeRenderer, atom, true);
1503
- atom = atom.sibling;
1504
- }
1505
- }
1506
- applyRefs();
1450
+ updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, context);
1507
1451
  };
1508
1452
  }
1509
- function updateComponent(newAtom, reusedAtom, expectIndex, oldIndex, nativeRenderer, context) {
1510
- return function (offset) {
1453
+ function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1454
+ return function (offset, needMove) {
1511
1455
  const component = reusedAtom.jsxNode;
1512
1456
  const newProps = newAtom.jsxNode.props;
1513
1457
  const oldTemplate = component.template;
1514
1458
  const newTemplate = component.update(newProps);
1515
1459
  const portalHost = component.instance.$portalHost;
1516
1460
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1517
- component.$$view = Object.assign({ atom: newAtom }, context);
1461
+ componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1518
1462
  newAtom.jsxNode = component;
1519
1463
  if (newTemplate === oldTemplate) {
1520
- reuseComponentView(nativeRenderer, newAtom, reusedAtom, context, expectIndex - offset !== oldIndex);
1521
- updateView(nativeRenderer, component);
1464
+ newAtom.child = reusedAtom.child;
1465
+ reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1466
+ component.rendered();
1522
1467
  return;
1523
1468
  }
1524
1469
  if (newTemplate) {
1525
1470
  newAtom.child = createChildChain(newTemplate, newAtom.isSvg);
1526
1471
  }
1527
1472
  if (newAtom.child) {
1528
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, expectIndex, oldIndex + offset);
1473
+ diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1529
1474
  }
1530
1475
  else if (reusedAtom.child) {
1531
1476
  let atom = reusedAtom.child;
1532
1477
  while (atom) {
1533
- cleanView(nativeRenderer, atom, false);
1478
+ cleanView(nativeRenderer, atom, true);
1534
1479
  atom = atom.sibling;
1535
1480
  }
1536
1481
  }
1537
1482
  component.rendered();
1538
1483
  };
1539
1484
  }
1540
- function reuseComponentView(nativeRenderer, newAtom, reusedAtom, context, moveView) {
1541
- let child = reusedAtom.child;
1542
- newAtom.child = child;
1485
+ function reuseComponentView(nativeRenderer, child, context, moveView) {
1543
1486
  const updateContext = (atom) => {
1544
1487
  if (atom.jsxNode instanceof Component) {
1545
1488
  let child = atom.child;
@@ -1561,13 +1504,21 @@ function reuseComponentView(nativeRenderer, newAtom, reusedAtom, context, moveVi
1561
1504
  child = child.sibling;
1562
1505
  }
1563
1506
  }
1507
+ function cleanElementChildren(atom, nativeRenderer) {
1508
+ let child = atom.child;
1509
+ nativeRenderer.cleanChildren(atom.nativeNode, atom.isSvg);
1510
+ while (child) {
1511
+ cleanView(nativeRenderer, child, false);
1512
+ child = child.sibling;
1513
+ }
1514
+ }
1564
1515
  function cleanView(nativeRenderer, atom, needClean) {
1565
1516
  if (atom.nativeNode) {
1566
- if (!needClean) {
1517
+ if (needClean) {
1567
1518
  nativeRenderer.remove(atom.nativeNode, atom.isSvg);
1568
- needClean = true;
1519
+ needClean = false;
1569
1520
  }
1570
- if (atom.type === 'element') {
1521
+ if (atom.type === ElementAtomType) {
1571
1522
  const ref = atom.jsxNode.props[refKey];
1572
1523
  applyRefs(ref, atom.nativeNode, false);
1573
1524
  }
@@ -1575,7 +1526,7 @@ function cleanView(nativeRenderer, atom, needClean) {
1575
1526
  let child = atom.child;
1576
1527
  while (child) {
1577
1528
  if (child.jsxNode instanceof Component && child.jsxNode.instance.$portalHost) {
1578
- needClean = false;
1529
+ needClean = true;
1579
1530
  }
1580
1531
  cleanView(nativeRenderer, child, needClean);
1581
1532
  child = child.sibling;
@@ -1588,7 +1539,7 @@ function componentRender(nativeRenderer, component, from, context) {
1588
1539
  const { template, portalHost } = component.render();
1589
1540
  from.child = createChildChain(template, from.isSvg);
1590
1541
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1591
- component.$$view = Object.assign({ atom: from }, context);
1542
+ componentViewCache.set(component, Object.assign({ atom: from }, context));
1592
1543
  let child = from.child;
1593
1544
  while (child) {
1594
1545
  buildView(nativeRenderer, component, child, context);
@@ -1596,49 +1547,26 @@ function componentRender(nativeRenderer, component, from, context) {
1596
1547
  }
1597
1548
  component.rendered();
1598
1549
  }
1599
- function createChainByJSXComponent(jsxNode, prevAtom, isSvg) {
1600
- const atom = {
1601
- type: 'component',
1602
- jsxNode,
1603
- sibling: null,
1604
- child: null,
1605
- nativeNode: null,
1606
- isSvg
1607
- };
1608
- prevAtom.sibling = atom;
1609
- return atom;
1610
- }
1611
- function createChainByJSXText(jsxNode, prevAtom, isSvg) {
1550
+ function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, isSvg, key) {
1612
1551
  const atom = {
1613
- type: 'text',
1552
+ type,
1553
+ index: prevAtom.index + 1,
1614
1554
  jsxNode,
1615
1555
  sibling: null,
1616
1556
  child: null,
1617
1557
  nativeNode: null,
1618
- isSvg
1558
+ isSvg,
1559
+ nodeType,
1560
+ key
1619
1561
  };
1620
1562
  prevAtom.sibling = atom;
1621
1563
  return atom;
1622
1564
  }
1623
- function createChainByJSXElement(element, prevAtom, isSvg) {
1624
- isSvg = isSvg || element.type === 'svg';
1625
- const atom = {
1626
- type: 'element',
1627
- jsxNode: element,
1628
- sibling: null,
1629
- child: null,
1630
- nativeNode: null,
1631
- isSvg
1632
- };
1633
- prevAtom.sibling = atom;
1634
- atom.child = createChildChain(element.props.children, isSvg);
1635
- return atom;
1636
- }
1637
1565
  function createChainByNode(jsxNode, prevAtom, isSvg) {
1638
1566
  const type = typeof jsxNode;
1639
1567
  if (jsxNode !== null && type !== 'undefined' && type !== 'boolean') {
1640
1568
  if (typeof jsxNode === 'string') {
1641
- return createChainByJSXText(jsxNode, prevAtom, isSvg);
1569
+ return createChainByJSXNode(TextAtomType, jsxNode, jsxNode, prevAtom, isSvg);
1642
1570
  }
1643
1571
  if (Array.isArray(jsxNode)) {
1644
1572
  return createChainByChildren(jsxNode, prevAtom, isSvg);
@@ -1646,13 +1574,14 @@ function createChainByNode(jsxNode, prevAtom, isSvg) {
1646
1574
  if (type === 'object') {
1647
1575
  const nodeType = typeof jsxNode.type;
1648
1576
  if (nodeType === 'string') {
1649
- return createChainByJSXElement(jsxNode, prevAtom, isSvg);
1577
+ return createChainByJSXNode(ElementAtomType, jsxNode, jsxNode.type, prevAtom, isSvg || jsxNode.type === 'svg', jsxNode.key);
1650
1578
  }
1651
1579
  else if (nodeType === 'function') {
1652
- return createChainByJSXComponent(jsxNode, prevAtom, isSvg);
1580
+ return createChainByJSXNode(ComponentAtomType, jsxNode, jsxNode.type, prevAtom, isSvg, jsxNode.key);
1653
1581
  }
1654
1582
  }
1655
- return createChainByJSXText(String(jsxNode), prevAtom, isSvg);
1583
+ const text = String(jsxNode);
1584
+ return createChainByJSXNode(TextAtomType, text, text, prevAtom, isSvg);
1656
1585
  }
1657
1586
  return prevAtom;
1658
1587
  }
@@ -1663,7 +1592,7 @@ function createChainByChildren(children, prevAtom, isSvg) {
1663
1592
  return prevAtom;
1664
1593
  }
1665
1594
  function createChildChain(template, isSvg) {
1666
- const beforeAtom = { sibling: null };
1595
+ const beforeAtom = { sibling: null, index: -1 };
1667
1596
  createChainByNode(template, beforeAtom, isSvg);
1668
1597
  return beforeAtom.sibling;
1669
1598
  }
@@ -1680,12 +1609,14 @@ function insertNode(nativeRenderer, atom, context) {
1680
1609
  nativeRenderer.insertAfter(atom.nativeNode, context.host, atom.isSvg);
1681
1610
  }
1682
1611
  }
1683
- function createElement(nativeRenderer, vNode, isSvg) {
1684
- const nativeNode = nativeRenderer.createElement(vNode.type, isSvg);
1685
- const props = vNode.props;
1612
+ function createElement(nativeRenderer, atom, parentComponent, context) {
1613
+ const { isSvg, jsxNode } = atom;
1614
+ const nativeNode = nativeRenderer.createElement(jsxNode.type, isSvg);
1615
+ const props = jsxNode.props;
1686
1616
  let bindingRefs;
1687
1617
  for (const key in props) {
1688
1618
  if (key === 'children') {
1619
+ atom.child = createChildChain(jsxNode.props.children, isSvg);
1689
1620
  continue;
1690
1621
  }
1691
1622
  if (key === 'class') {
@@ -1705,7 +1636,7 @@ function createElement(nativeRenderer, vNode, isSvg) {
1705
1636
  if (listenerReg.test(key)) {
1706
1637
  const listener = props[key];
1707
1638
  if (typeof listener === 'function') {
1708
- bindEvent(nativeRenderer, vNode, key, nativeNode, listener, isSvg);
1639
+ nativeRenderer.listen(nativeNode, key, listener, isSvg);
1709
1640
  }
1710
1641
  continue;
1711
1642
  }
@@ -1715,21 +1646,32 @@ function createElement(nativeRenderer, vNode, isSvg) {
1715
1646
  }
1716
1647
  nativeRenderer.setProperty(nativeNode, key, props[key], isSvg);
1717
1648
  }
1718
- return {
1719
- nativeNode,
1720
- applyRefs: () => {
1721
- applyRefs(bindingRefs, nativeNode, true);
1722
- }
1723
- };
1724
- }
1725
- function createTextNode(nativeRenderer, text, isSvg) {
1726
- return nativeRenderer.createTextNode(text, isSvg);
1727
- }
1728
- function updateNativeNodeProperties(nativeRenderer, newVNode, oldVNode, nativeNode, isSvg) {
1649
+ atom.nativeNode = nativeNode;
1650
+ insertNode(nativeRenderer, atom, context);
1651
+ buildElementChildren(atom, nativeRenderer, parentComponent, context);
1652
+ context.host = nativeNode;
1653
+ context.isParent = false;
1654
+ applyRefs(bindingRefs, nativeNode, true);
1655
+ }
1656
+ function createTextNode(nativeRenderer, atom, context) {
1657
+ const nativeNode = nativeRenderer.createTextNode(atom.jsxNode, atom.isSvg);
1658
+ atom.nativeNode = nativeNode;
1659
+ insertNode(nativeRenderer, atom, context);
1660
+ context.host = nativeNode;
1661
+ context.isParent = false;
1662
+ }
1663
+ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, context) {
1664
+ const newVNode = newAtom.jsxNode;
1665
+ const isSvg = newAtom.isSvg;
1666
+ const nativeNode = newAtom.nativeNode;
1667
+ const oldVNode = oldAtom.jsxNode;
1668
+ if (newVNode === oldVNode) {
1669
+ updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1670
+ return;
1671
+ }
1729
1672
  const changes = getObjectChanges(newVNode.props, oldVNode.props);
1730
1673
  let unBindRefs;
1731
1674
  let bindRefs;
1732
- newVNode.on = oldVNode.on;
1733
1675
  for (const [key, value] of changes.remove) {
1734
1676
  if (key === 'children') {
1735
1677
  continue;
@@ -1746,10 +1688,7 @@ function updateNativeNodeProperties(nativeRenderer, newVNode, oldVNode, nativeNo
1746
1688
  }
1747
1689
  if (listenerReg.test(key)) {
1748
1690
  if (typeof value === 'function') {
1749
- const type = key.replace(listenerReg, '').toLowerCase();
1750
- const oldOn = oldVNode.on;
1751
- nativeRenderer.unListen(nativeNode, type, oldOn[type].delegate, isSvg);
1752
- Reflect.deleteProperty(oldOn, type);
1691
+ nativeRenderer.unListen(nativeNode, key, value, isSvg);
1753
1692
  }
1754
1693
  continue;
1755
1694
  }
@@ -1782,8 +1721,8 @@ function updateNativeNodeProperties(nativeRenderer, newVNode, oldVNode, nativeNo
1782
1721
  continue;
1783
1722
  }
1784
1723
  if (listenerReg.test(key)) {
1785
- const listenType = key.replace(listenerReg, '').toLowerCase();
1786
- newVNode.on[listenType].listenFn = newValue;
1724
+ nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1725
+ nativeRenderer.listen(nativeNode, key, newValue, isSvg);
1787
1726
  continue;
1788
1727
  }
1789
1728
  if (key === refKey) {
@@ -1810,7 +1749,7 @@ function updateNativeNodeProperties(nativeRenderer, newVNode, oldVNode, nativeNo
1810
1749
  }
1811
1750
  if (listenerReg.test(key)) {
1812
1751
  if (typeof value === 'function') {
1813
- bindEvent(nativeRenderer, newVNode, key, nativeNode, value, isSvg);
1752
+ nativeRenderer.listen(nativeNode, key, value, isSvg);
1814
1753
  }
1815
1754
  continue;
1816
1755
  }
@@ -1820,10 +1759,36 @@ function updateNativeNodeProperties(nativeRenderer, newVNode, oldVNode, nativeNo
1820
1759
  }
1821
1760
  nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1822
1761
  }
1823
- return () => {
1824
- applyRefs(unBindRefs, nativeNode, false);
1825
- applyRefs(bindRefs, nativeNode, true);
1826
- };
1762
+ updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1763
+ applyRefs(unBindRefs, nativeNode, false);
1764
+ applyRefs(bindRefs, nativeNode, true);
1765
+ }
1766
+ function updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg) {
1767
+ /**
1768
+ * 不能仅依赖 children 是否相等的判断来确定是否要继续向下 diff
1769
+ * 如:
1770
+ * ```tsx
1771
+ * <Comp>
1772
+ * <div>
1773
+ * {props.children}
1774
+ * </div>
1775
+ * </Comp>
1776
+ * ```
1777
+ * 其中当 Comp 产生变化时,children 来自父组件,这时 children 是相等的,
1778
+ * 但,children 内可能有子组件也发生了变化,如果不继续 diff,那么,子组件
1779
+ * 的视图更新将不会发生
1780
+ */
1781
+ newAtom.child = createChildChain(newAtom.jsxNode.props.children, isSvg);
1782
+ if (!newAtom.child) {
1783
+ cleanElementChildren(oldAtom, nativeRenderer);
1784
+ }
1785
+ else {
1786
+ diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, {
1787
+ host: newAtom.nativeNode,
1788
+ isParent: true,
1789
+ rootHost: context.rootHost
1790
+ }, false);
1791
+ }
1827
1792
  }
1828
1793
  function applyRefs(refs, nativeNode, binding) {
1829
1794
  if (refs) {
@@ -1835,21 +1800,6 @@ function applyRefs(refs, nativeNode, binding) {
1835
1800
  }
1836
1801
  }
1837
1802
  }
1838
- function bindEvent(nativeRenderer, vNode, key, nativeNode, listenFn, isSvg) {
1839
- let on = vNode.on;
1840
- if (!on) {
1841
- vNode.on = on = {};
1842
- }
1843
- const type = key.replace(listenerReg, '').toLowerCase();
1844
- const delegateObj = {
1845
- delegate(...args) {
1846
- return delegateObj.listenFn.apply(this, args);
1847
- },
1848
- listenFn
1849
- };
1850
- on[type] = delegateObj;
1851
- nativeRenderer.listen(nativeNode, type, delegateObj.delegate, isSvg);
1852
- }
1853
1803
 
1854
1804
  /**
1855
1805
  * Viewfly 根组件,用于实现组件状态更新事件通知