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

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