@tarojs/router 3.6.29 → 3.6.31-canary.0

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/dist/api.js CHANGED
@@ -16,13 +16,14 @@ function processNavigateUrl(option) {
16
16
  const parts = routesAlias.getOrigin(history.location.pathname).split('/');
17
17
  parts.pop();
18
18
  pathPieces.pathname.split('/').forEach((item) => {
19
- if (item === '.') {
19
+ if (item === '.')
20
20
  return;
21
- }
22
21
  item === '..' ? parts.pop() : parts.push(item);
23
22
  });
24
23
  pathPieces.pathname = parts.join('/');
25
24
  }
25
+ // 确保是 / 开头的路径
26
+ pathPieces.pathname = addLeadingSlash(pathPieces.pathname);
26
27
  // 处理自定义路由
27
28
  pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
28
29
  // 处理 basename
@@ -50,20 +51,10 @@ function navigate(option, method) {
50
51
  });
51
52
  try {
52
53
  if ('url' in option) {
53
- if (!RouterConfig.isPage(addLeadingSlash(option.url))) {
54
- const res = { errMsg: `${method}:fail page ${option.url} is not found` };
55
- fail === null || fail === void 0 ? void 0 : fail(res);
56
- complete === null || complete === void 0 ? void 0 : complete(res);
57
- if (fail || complete) {
58
- return resolve(res);
59
- }
60
- else {
61
- return reject(res);
62
- }
63
- }
64
54
  const pathPieces = processNavigateUrl(option);
65
55
  const state = { timestamp: Date.now() };
66
56
  if (method === 'navigateTo') {
57
+ // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
67
58
  history.push(pathPieces, state);
68
59
  }
69
60
  else if (method === 'redirectTo' || method === 'switchTab') {
package/dist/index.cjs.js CHANGED
@@ -15,7 +15,8 @@ var UniversalRouter = require('universal-router');
15
15
  function loadAnimateStyle(ms = 300) {
16
16
  const css = `
17
17
  body {
18
- overflow: hidden; // 防止 iOS 页面滚动
18
+ /* 防止 iOS 页面滚动 */
19
+ overflow: hidden;
19
20
  }
20
21
  .taro_router > .taro_page {
21
22
  position: absolute;
@@ -142,7 +143,7 @@ function loadNavigationBarStyle() {
142
143
  to {
143
144
  transform: rotate(360deg);
144
145
  }
145
- }
146
+ }
146
147
 
147
148
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
148
149
  display: none;
@@ -535,13 +536,14 @@ function processNavigateUrl(option) {
535
536
  const parts = routesAlias.getOrigin(exports.history.location.pathname).split('/');
536
537
  parts.pop();
537
538
  pathPieces.pathname.split('/').forEach((item) => {
538
- if (item === '.') {
539
+ if (item === '.')
539
540
  return;
540
- }
541
541
  item === '..' ? parts.pop() : parts.push(item);
542
542
  });
543
543
  pathPieces.pathname = parts.join('/');
544
544
  }
545
+ // 确保是 / 开头的路径
546
+ pathPieces.pathname = runtime.addLeadingSlash(pathPieces.pathname);
545
547
  // 处理自定义路由
546
548
  pathPieces.pathname = routesAlias.getAlias(runtime.addLeadingSlash(pathPieces.pathname));
547
549
  // 处理 basename
@@ -569,20 +571,10 @@ function navigate(option, method) {
569
571
  });
570
572
  try {
571
573
  if ('url' in option) {
572
- if (!RouterConfig.isPage(runtime.addLeadingSlash(option.url))) {
573
- const res = { errMsg: `${method}:fail page ${option.url} is not found` };
574
- fail === null || fail === void 0 ? void 0 : fail(res);
575
- complete === null || complete === void 0 ? void 0 : complete(res);
576
- if (fail || complete) {
577
- return resolve(res);
578
- }
579
- else {
580
- return reject(res);
581
- }
582
- }
583
574
  const pathPieces = processNavigateUrl(option);
584
575
  const state = { timestamp: Date.now() };
585
576
  if (method === 'navigateTo') {
577
+ // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
586
578
  exports.history.push(pathPieces, state);
587
579
  }
588
580
  else if (method === 'redirectTo' || method === 'switchTab') {
@@ -975,7 +967,7 @@ class NavigationBarHandler {
975
967
  this.setNavigationLoading();
976
968
  }
977
969
  setCacheValue() {
978
- const currentPage = this.pageContext.currentPage;
970
+ const currentPage = this.pageContext.originPathname;
979
971
  if (typeof this.cache[currentPage] !== 'object') {
980
972
  this.cache[currentPage] = {};
981
973
  }
@@ -1006,7 +998,7 @@ class NavigationBarHandler {
1006
998
  var _a;
1007
999
  if (!this.navigationBarElement)
1008
1000
  return;
1009
- const currentPage = this.pageContext.currentPage;
1001
+ const currentPage = this.pageContext.originPathname;
1010
1002
  let isShow;
1011
1003
  if (typeof show === 'boolean') {
1012
1004
  isShow = show;
@@ -1031,7 +1023,7 @@ class NavigationBarHandler {
1031
1023
  var _a, _b, _c;
1032
1024
  if (!this.navigationBarElement)
1033
1025
  return;
1034
- const currentPage = this.pageContext.currentPage;
1026
+ const currentPage = this.pageContext.originPathname;
1035
1027
  let color;
1036
1028
  if (typeof backgroundColor === 'string') {
1037
1029
  color = backgroundColor;
@@ -1055,7 +1047,7 @@ class NavigationBarHandler {
1055
1047
  var _a, _b, _c;
1056
1048
  if (!this.navigationBarElement)
1057
1049
  return;
1058
- const currentPage = this.pageContext.currentPage;
1050
+ const currentPage = this.pageContext.originPathname;
1059
1051
  let color;
1060
1052
  if (typeof fontColor === 'string') {
1061
1053
  color = fontColor;
@@ -1077,7 +1069,7 @@ class NavigationBarHandler {
1077
1069
  }
1078
1070
  setTitle(title) {
1079
1071
  var _a, _b, _c;
1080
- const currentPage = this.pageContext.currentPage;
1072
+ const currentPage = this.pageContext.originPathname;
1081
1073
  let proceedTitle;
1082
1074
  if (typeof title === 'string') {
1083
1075
  proceedTitle = title;
@@ -1192,14 +1184,14 @@ class PageHandler {
1192
1184
  }
1193
1185
  set pathname(p) { this.router.pathname = p; }
1194
1186
  get pathname() { return this.router.pathname; }
1187
+ // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
1188
+ get originPathname() { return routesAlias.getOrigin(runtime.addLeadingSlash(runtime.stripBasename(this.pathname, this.basename))); }
1195
1189
  get basename() { return this.router.basename || ''; }
1196
1190
  get pageConfig() {
1197
- const routePath = runtime.addLeadingSlash(runtime.stripBasename(this.pathname, this.basename));
1198
1191
  const homePage = runtime.addLeadingSlash(this.homePage);
1199
1192
  return this.routes.find(r => {
1200
- var _a;
1201
1193
  const pagePath = runtime.addLeadingSlash(r.path);
1202
- return [pagePath, homePage].includes(routePath) || ((_a = routesAlias.getConfig(pagePath)) === null || _a === void 0 ? void 0 : _a.includes(routePath));
1194
+ return [pagePath, homePage].includes(this.originPathname);
1203
1195
  });
1204
1196
  }
1205
1197
  isTabBar(pathname) {
@@ -1488,6 +1480,10 @@ function createRouter(history$1, app, config, framework) {
1488
1480
  }
1489
1481
  RouterConfig.config = config;
1490
1482
  const handler = new PageHandler(config, history$1);
1483
+ // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
1484
+ // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
1485
+ // 所以需要加一个锁来应对这个情况
1486
+ const pageLock = {};
1491
1487
  routesAlias.set(handler.router.customRoutes);
1492
1488
  const basename = handler.router.basename;
1493
1489
  const routes = handler.routes.map(route => {
@@ -1511,24 +1507,30 @@ function createRouter(history$1, app, config, framework) {
1511
1507
  app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
1512
1508
  const render = ({ location, action }) => tslib.__awaiter(this, void 0, void 0, function* () {
1513
1509
  var _c, _d, _e, _f, _g, _h, _j, _k;
1514
- handler.pathname = decodeURI(location.pathname);
1510
+ // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
1511
+ const currentPathname = decodeURI(location.pathname);
1515
1512
  if ((_c = window.__taroAppConfig) === null || _c === void 0 ? void 0 : _c.usingWindowScroll)
1516
1513
  window.scrollTo(0, 0);
1517
1514
  runtime.eventCenter.trigger('__taroRouterChange', {
1518
1515
  toLocation: {
1519
- path: handler.pathname
1516
+ path: currentPathname
1520
1517
  }
1521
1518
  });
1522
- let element, params;
1519
+ let element, context, params;
1520
+ const routerPath = handler.router.forcePath || currentPathname;
1521
+ pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
1522
+ const currentLock = pageLock[routerPath];
1523
+ let postLock;
1523
1524
  try {
1524
- const result = yield router.resolve(handler.router.forcePath || handler.pathname);
1525
- [element, , params] = yield Promise.all(result);
1525
+ const result = yield router.resolve(routerPath);
1526
+ [element, context, params] = yield Promise.all(result);
1527
+ postLock = pageLock[routerPath];
1526
1528
  }
1527
1529
  catch (error) {
1528
1530
  if (error.status === 404) {
1529
1531
  const notFoundEvent = {
1530
1532
  isEntryPage: stacks.length === 0,
1531
- path: handler.pathname,
1533
+ path: currentPathname,
1532
1534
  query: handler.getQuery(createStampId()),
1533
1535
  };
1534
1536
  (_d = app.onPageNotFound) === null || _d === void 0 ? void 0 : _d.call(app, notFoundEvent);
@@ -1542,9 +1544,12 @@ function createRouter(history$1, app, config, framework) {
1542
1544
  throw error;
1543
1545
  }
1544
1546
  }
1545
- if (!element)
1547
+ if (!element || currentLock !== postLock)
1546
1548
  return;
1547
- const pageConfig = handler.pageConfig;
1549
+ // Note: 异步结束后,在设置 handler.pathname
1550
+ // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
1551
+ handler.pathname = context.pathname;
1552
+ const { pathname, pageConfig } = handler;
1548
1553
  let enablePullDownRefresh = ((_e = config === null || config === void 0 ? void 0 : config.window) === null || _e === void 0 ? void 0 : _e.enablePullDownRefresh) || false;
1549
1554
  let navigationStyle = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.navigationStyle) || 'default';
1550
1555
  let navigationBarTextStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationBarTextStyle) || 'white';
@@ -1565,7 +1570,6 @@ function createRouter(history$1, app, config, framework) {
1565
1570
  }
1566
1571
  runtime.eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
1567
1572
  const currentPage = runtime.Current.page;
1568
- const pathname = handler.pathname;
1569
1573
  const methodName = (_j = stacks.method) !== null && _j !== void 0 ? _j : '';
1570
1574
  const cacheTabs = stacks.getTabs();
1571
1575
  let shouldLoad = false;
@@ -1581,7 +1585,7 @@ function createRouter(history$1, app, config, framework) {
1581
1585
  }
1582
1586
  shouldLoad = true;
1583
1587
  }
1584
- else if (currentPage && handler.isTabBar(handler.pathname)) {
1588
+ else if (currentPage && handler.isTabBar(pathname)) {
1585
1589
  if (handler.isSamePage(currentPage))
1586
1590
  return;
1587
1591
  if (handler.isTabBar(currentPage.path)) {
@@ -1599,8 +1603,8 @@ function createRouter(history$1, app, config, framework) {
1599
1603
  handler.unload(currentPage, stacks.length, true);
1600
1604
  }
1601
1605
  }
1602
- if (cacheTabs[handler.pathname]) {
1603
- stacks.popTab(handler.pathname);
1606
+ if (cacheTabs[pathname]) {
1607
+ stacks.popTab(pathname);
1604
1608
  return handler.show(stacks.getItem(0), pageConfig, 0);
1605
1609
  }
1606
1610
  shouldLoad = true;
package/dist/index.esm.js CHANGED
@@ -14,7 +14,8 @@ import UniversalRouter from 'universal-router';
14
14
  function loadAnimateStyle(ms = 300) {
15
15
  const css = `
16
16
  body {
17
- overflow: hidden; // 防止 iOS 页面滚动
17
+ /* 防止 iOS 页面滚动 */
18
+ overflow: hidden;
18
19
  }
19
20
  .taro_router > .taro_page {
20
21
  position: absolute;
@@ -141,7 +142,7 @@ function loadNavigationBarStyle() {
141
142
  to {
142
143
  transform: rotate(360deg);
143
144
  }
144
- }
145
+ }
145
146
 
146
147
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
147
148
  display: none;
@@ -534,13 +535,14 @@ function processNavigateUrl(option) {
534
535
  const parts = routesAlias.getOrigin(history.location.pathname).split('/');
535
536
  parts.pop();
536
537
  pathPieces.pathname.split('/').forEach((item) => {
537
- if (item === '.') {
538
+ if (item === '.')
538
539
  return;
539
- }
540
540
  item === '..' ? parts.pop() : parts.push(item);
541
541
  });
542
542
  pathPieces.pathname = parts.join('/');
543
543
  }
544
+ // 确保是 / 开头的路径
545
+ pathPieces.pathname = addLeadingSlash(pathPieces.pathname);
544
546
  // 处理自定义路由
545
547
  pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
546
548
  // 处理 basename
@@ -568,20 +570,10 @@ function navigate(option, method) {
568
570
  });
569
571
  try {
570
572
  if ('url' in option) {
571
- if (!RouterConfig.isPage(addLeadingSlash(option.url))) {
572
- const res = { errMsg: `${method}:fail page ${option.url} is not found` };
573
- fail === null || fail === void 0 ? void 0 : fail(res);
574
- complete === null || complete === void 0 ? void 0 : complete(res);
575
- if (fail || complete) {
576
- return resolve(res);
577
- }
578
- else {
579
- return reject(res);
580
- }
581
- }
582
573
  const pathPieces = processNavigateUrl(option);
583
574
  const state = { timestamp: Date.now() };
584
575
  if (method === 'navigateTo') {
576
+ // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
585
577
  history.push(pathPieces, state);
586
578
  }
587
579
  else if (method === 'redirectTo' || method === 'switchTab') {
@@ -974,7 +966,7 @@ class NavigationBarHandler {
974
966
  this.setNavigationLoading();
975
967
  }
976
968
  setCacheValue() {
977
- const currentPage = this.pageContext.currentPage;
969
+ const currentPage = this.pageContext.originPathname;
978
970
  if (typeof this.cache[currentPage] !== 'object') {
979
971
  this.cache[currentPage] = {};
980
972
  }
@@ -1005,7 +997,7 @@ class NavigationBarHandler {
1005
997
  var _a;
1006
998
  if (!this.navigationBarElement)
1007
999
  return;
1008
- const currentPage = this.pageContext.currentPage;
1000
+ const currentPage = this.pageContext.originPathname;
1009
1001
  let isShow;
1010
1002
  if (typeof show === 'boolean') {
1011
1003
  isShow = show;
@@ -1030,7 +1022,7 @@ class NavigationBarHandler {
1030
1022
  var _a, _b, _c;
1031
1023
  if (!this.navigationBarElement)
1032
1024
  return;
1033
- const currentPage = this.pageContext.currentPage;
1025
+ const currentPage = this.pageContext.originPathname;
1034
1026
  let color;
1035
1027
  if (typeof backgroundColor === 'string') {
1036
1028
  color = backgroundColor;
@@ -1054,7 +1046,7 @@ class NavigationBarHandler {
1054
1046
  var _a, _b, _c;
1055
1047
  if (!this.navigationBarElement)
1056
1048
  return;
1057
- const currentPage = this.pageContext.currentPage;
1049
+ const currentPage = this.pageContext.originPathname;
1058
1050
  let color;
1059
1051
  if (typeof fontColor === 'string') {
1060
1052
  color = fontColor;
@@ -1076,7 +1068,7 @@ class NavigationBarHandler {
1076
1068
  }
1077
1069
  setTitle(title) {
1078
1070
  var _a, _b, _c;
1079
- const currentPage = this.pageContext.currentPage;
1071
+ const currentPage = this.pageContext.originPathname;
1080
1072
  let proceedTitle;
1081
1073
  if (typeof title === 'string') {
1082
1074
  proceedTitle = title;
@@ -1191,14 +1183,14 @@ class PageHandler {
1191
1183
  }
1192
1184
  set pathname(p) { this.router.pathname = p; }
1193
1185
  get pathname() { return this.router.pathname; }
1186
+ // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
1187
+ get originPathname() { return routesAlias.getOrigin(addLeadingSlash(stripBasename(this.pathname, this.basename))); }
1194
1188
  get basename() { return this.router.basename || ''; }
1195
1189
  get pageConfig() {
1196
- const routePath = addLeadingSlash(stripBasename(this.pathname, this.basename));
1197
1190
  const homePage = addLeadingSlash(this.homePage);
1198
1191
  return this.routes.find(r => {
1199
- var _a;
1200
1192
  const pagePath = addLeadingSlash(r.path);
1201
- return [pagePath, homePage].includes(routePath) || ((_a = routesAlias.getConfig(pagePath)) === null || _a === void 0 ? void 0 : _a.includes(routePath));
1193
+ return [pagePath, homePage].includes(this.originPathname);
1202
1194
  });
1203
1195
  }
1204
1196
  isTabBar(pathname) {
@@ -1487,6 +1479,10 @@ function createRouter(history, app, config, framework) {
1487
1479
  }
1488
1480
  RouterConfig.config = config;
1489
1481
  const handler = new PageHandler(config, history);
1482
+ // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
1483
+ // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
1484
+ // 所以需要加一个锁来应对这个情况
1485
+ const pageLock = {};
1490
1486
  routesAlias.set(handler.router.customRoutes);
1491
1487
  const basename = handler.router.basename;
1492
1488
  const routes = handler.routes.map(route => {
@@ -1510,24 +1506,30 @@ function createRouter(history, app, config, framework) {
1510
1506
  app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
1511
1507
  const render = ({ location, action }) => __awaiter(this, void 0, void 0, function* () {
1512
1508
  var _c, _d, _e, _f, _g, _h, _j, _k;
1513
- handler.pathname = decodeURI(location.pathname);
1509
+ // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
1510
+ const currentPathname = decodeURI(location.pathname);
1514
1511
  if ((_c = window.__taroAppConfig) === null || _c === void 0 ? void 0 : _c.usingWindowScroll)
1515
1512
  window.scrollTo(0, 0);
1516
1513
  eventCenter.trigger('__taroRouterChange', {
1517
1514
  toLocation: {
1518
- path: handler.pathname
1515
+ path: currentPathname
1519
1516
  }
1520
1517
  });
1521
- let element, params;
1518
+ let element, context, params;
1519
+ const routerPath = handler.router.forcePath || currentPathname;
1520
+ pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
1521
+ const currentLock = pageLock[routerPath];
1522
+ let postLock;
1522
1523
  try {
1523
- const result = yield router.resolve(handler.router.forcePath || handler.pathname);
1524
- [element, , params] = yield Promise.all(result);
1524
+ const result = yield router.resolve(routerPath);
1525
+ [element, context, params] = yield Promise.all(result);
1526
+ postLock = pageLock[routerPath];
1525
1527
  }
1526
1528
  catch (error) {
1527
1529
  if (error.status === 404) {
1528
1530
  const notFoundEvent = {
1529
1531
  isEntryPage: stacks.length === 0,
1530
- path: handler.pathname,
1532
+ path: currentPathname,
1531
1533
  query: handler.getQuery(createStampId()),
1532
1534
  };
1533
1535
  (_d = app.onPageNotFound) === null || _d === void 0 ? void 0 : _d.call(app, notFoundEvent);
@@ -1541,9 +1543,12 @@ function createRouter(history, app, config, framework) {
1541
1543
  throw error;
1542
1544
  }
1543
1545
  }
1544
- if (!element)
1546
+ if (!element || currentLock !== postLock)
1545
1547
  return;
1546
- const pageConfig = handler.pageConfig;
1548
+ // Note: 异步结束后,在设置 handler.pathname
1549
+ // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
1550
+ handler.pathname = context.pathname;
1551
+ const { pathname, pageConfig } = handler;
1547
1552
  let enablePullDownRefresh = ((_e = config === null || config === void 0 ? void 0 : config.window) === null || _e === void 0 ? void 0 : _e.enablePullDownRefresh) || false;
1548
1553
  let navigationStyle = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.navigationStyle) || 'default';
1549
1554
  let navigationBarTextStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationBarTextStyle) || 'white';
@@ -1564,7 +1569,6 @@ function createRouter(history, app, config, framework) {
1564
1569
  }
1565
1570
  eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
1566
1571
  const currentPage = Current.page;
1567
- const pathname = handler.pathname;
1568
1572
  const methodName = (_j = stacks.method) !== null && _j !== void 0 ? _j : '';
1569
1573
  const cacheTabs = stacks.getTabs();
1570
1574
  let shouldLoad = false;
@@ -1580,7 +1584,7 @@ function createRouter(history, app, config, framework) {
1580
1584
  }
1581
1585
  shouldLoad = true;
1582
1586
  }
1583
- else if (currentPage && handler.isTabBar(handler.pathname)) {
1587
+ else if (currentPage && handler.isTabBar(pathname)) {
1584
1588
  if (handler.isSamePage(currentPage))
1585
1589
  return;
1586
1590
  if (handler.isTabBar(currentPage.path)) {
@@ -1598,8 +1602,8 @@ function createRouter(history, app, config, framework) {
1598
1602
  handler.unload(currentPage, stacks.length, true);
1599
1603
  }
1600
1604
  }
1601
- if (cacheTabs[handler.pathname]) {
1602
- stacks.popTab(handler.pathname);
1605
+ if (cacheTabs[pathname]) {
1606
+ stacks.popTab(pathname);
1603
1607
  return handler.show(stacks.getItem(0), pageConfig, 0);
1604
1608
  }
1605
1609
  shouldLoad = true;
@@ -73,7 +73,7 @@ class NavigationBarHandler {
73
73
  this.setNavigationLoading();
74
74
  }
75
75
  setCacheValue() {
76
- const currentPage = this.pageContext.currentPage;
76
+ const currentPage = this.pageContext.originPathname;
77
77
  if (typeof this.cache[currentPage] !== 'object') {
78
78
  this.cache[currentPage] = {};
79
79
  }
@@ -104,7 +104,7 @@ class NavigationBarHandler {
104
104
  var _a;
105
105
  if (!this.navigationBarElement)
106
106
  return;
107
- const currentPage = this.pageContext.currentPage;
107
+ const currentPage = this.pageContext.originPathname;
108
108
  let isShow;
109
109
  if (typeof show === 'boolean') {
110
110
  isShow = show;
@@ -129,7 +129,7 @@ class NavigationBarHandler {
129
129
  var _a, _b, _c;
130
130
  if (!this.navigationBarElement)
131
131
  return;
132
- const currentPage = this.pageContext.currentPage;
132
+ const currentPage = this.pageContext.originPathname;
133
133
  let color;
134
134
  if (typeof backgroundColor === 'string') {
135
135
  color = backgroundColor;
@@ -153,7 +153,7 @@ class NavigationBarHandler {
153
153
  var _a, _b, _c;
154
154
  if (!this.navigationBarElement)
155
155
  return;
156
- const currentPage = this.pageContext.currentPage;
156
+ const currentPage = this.pageContext.originPathname;
157
157
  let color;
158
158
  if (typeof fontColor === 'string') {
159
159
  color = fontColor;
@@ -175,7 +175,7 @@ class NavigationBarHandler {
175
175
  }
176
176
  setTitle(title) {
177
177
  var _a, _b, _c;
178
- const currentPage = this.pageContext.currentPage;
178
+ const currentPage = this.pageContext.originPathname;
179
179
  let proceedTitle;
180
180
  if (typeof title === 'string') {
181
181
  proceedTitle = title;
@@ -28,6 +28,7 @@ declare class PageHandler {
28
28
  get animationDuration(): number;
29
29
  set pathname(p: string);
30
30
  get pathname(): string;
31
+ get originPathname(): string;
31
32
  get basename(): string;
32
33
  get pageConfig(): Route | undefined;
33
34
  isTabBar(pathname: string): boolean;
@@ -49,14 +49,14 @@ class PageHandler {
49
49
  }
50
50
  set pathname(p) { this.router.pathname = p; }
51
51
  get pathname() { return this.router.pathname; }
52
+ // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
53
+ get originPathname() { return routesAlias.getOrigin(addLeadingSlash(stripBasename(this.pathname, this.basename))); }
52
54
  get basename() { return this.router.basename || ''; }
53
55
  get pageConfig() {
54
- const routePath = addLeadingSlash(stripBasename(this.pathname, this.basename));
55
56
  const homePage = addLeadingSlash(this.homePage);
56
57
  return this.routes.find(r => {
57
- var _a;
58
58
  const pagePath = addLeadingSlash(r.path);
59
- return [pagePath, homePage].includes(routePath) || ((_a = routesAlias.getConfig(pagePath)) === null || _a === void 0 ? void 0 : _a.includes(routePath));
59
+ return [pagePath, homePage].includes(this.originPathname);
60
60
  });
61
61
  }
62
62
  isTabBar(pathname) {
@@ -17,6 +17,10 @@ function createRouter(history, app, config, framework) {
17
17
  }
18
18
  RouterConfig.config = config;
19
19
  const handler = new PageHandler(config, history);
20
+ // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
21
+ // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
22
+ // 所以需要加一个锁来应对这个情况
23
+ const pageLock = {};
20
24
  routesAlias.set(handler.router.customRoutes);
21
25
  const basename = handler.router.basename;
22
26
  const routes = handler.routes.map(route => {
@@ -40,24 +44,30 @@ function createRouter(history, app, config, framework) {
40
44
  app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
41
45
  const render = ({ location, action }) => __awaiter(this, void 0, void 0, function* () {
42
46
  var _c, _d, _e, _f, _g, _h, _j, _k;
43
- handler.pathname = decodeURI(location.pathname);
47
+ // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
48
+ const currentPathname = decodeURI(location.pathname);
44
49
  if ((_c = window.__taroAppConfig) === null || _c === void 0 ? void 0 : _c.usingWindowScroll)
45
50
  window.scrollTo(0, 0);
46
51
  eventCenter.trigger('__taroRouterChange', {
47
52
  toLocation: {
48
- path: handler.pathname
53
+ path: currentPathname
49
54
  }
50
55
  });
51
- let element, params;
56
+ let element, context, params;
57
+ const routerPath = handler.router.forcePath || currentPathname;
58
+ pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
59
+ const currentLock = pageLock[routerPath];
60
+ let postLock;
52
61
  try {
53
- const result = yield router.resolve(handler.router.forcePath || handler.pathname);
54
- [element, , params] = yield Promise.all(result);
62
+ const result = yield router.resolve(routerPath);
63
+ [element, context, params] = yield Promise.all(result);
64
+ postLock = pageLock[routerPath];
55
65
  }
56
66
  catch (error) {
57
67
  if (error.status === 404) {
58
68
  const notFoundEvent = {
59
69
  isEntryPage: stacks.length === 0,
60
- path: handler.pathname,
70
+ path: currentPathname,
61
71
  query: handler.getQuery(createStampId()),
62
72
  };
63
73
  (_d = app.onPageNotFound) === null || _d === void 0 ? void 0 : _d.call(app, notFoundEvent);
@@ -71,9 +81,12 @@ function createRouter(history, app, config, framework) {
71
81
  throw error;
72
82
  }
73
83
  }
74
- if (!element)
84
+ if (!element || currentLock !== postLock)
75
85
  return;
76
- const pageConfig = handler.pageConfig;
86
+ // Note: 异步结束后,在设置 handler.pathname
87
+ // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
88
+ handler.pathname = context.pathname;
89
+ const { pathname, pageConfig } = handler;
77
90
  let enablePullDownRefresh = ((_e = config === null || config === void 0 ? void 0 : config.window) === null || _e === void 0 ? void 0 : _e.enablePullDownRefresh) || false;
78
91
  let navigationStyle = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.navigationStyle) || 'default';
79
92
  let navigationBarTextStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationBarTextStyle) || 'white';
@@ -94,7 +107,6 @@ function createRouter(history, app, config, framework) {
94
107
  }
95
108
  eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
96
109
  const currentPage = Current.page;
97
- const pathname = handler.pathname;
98
110
  const methodName = (_j = stacks.method) !== null && _j !== void 0 ? _j : '';
99
111
  const cacheTabs = stacks.getTabs();
100
112
  let shouldLoad = false;
@@ -110,7 +122,7 @@ function createRouter(history, app, config, framework) {
110
122
  }
111
123
  shouldLoad = true;
112
124
  }
113
- else if (currentPage && handler.isTabBar(handler.pathname)) {
125
+ else if (currentPage && handler.isTabBar(pathname)) {
114
126
  if (handler.isSamePage(currentPage))
115
127
  return;
116
128
  if (handler.isTabBar(currentPage.path)) {
@@ -128,8 +140,8 @@ function createRouter(history, app, config, framework) {
128
140
  handler.unload(currentPage, stacks.length, true);
129
141
  }
130
142
  }
131
- if (cacheTabs[handler.pathname]) {
132
- stacks.popTab(handler.pathname);
143
+ if (cacheTabs[pathname]) {
144
+ stacks.popTab(pathname);
133
145
  return handler.show(stacks.getItem(0), pageConfig, 0);
134
146
  }
135
147
  shouldLoad = true;
package/dist/style.js CHANGED
@@ -4,7 +4,8 @@
4
4
  function loadAnimateStyle(ms = 300) {
5
5
  const css = `
6
6
  body {
7
- overflow: hidden; // 防止 iOS 页面滚动
7
+ /* 防止 iOS 页面滚动 */
8
+ overflow: hidden;
8
9
  }
9
10
  .taro_router > .taro_page {
10
11
  position: absolute;
@@ -131,7 +132,7 @@ function loadNavigationBarStyle() {
131
132
  to {
132
133
  transform: rotate(360deg);
133
134
  }
134
- }
135
+ }
135
136
 
136
137
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
137
138
  display: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarojs/router",
3
- "version": "3.6.29",
3
+ "version": "3.6.31-canary.0",
4
4
  "description": "Taro-router",
5
5
  "browser": "dist/index.js",
6
6
  "main:h5": "dist/index.esm.js",
@@ -44,14 +44,14 @@
44
44
  "rollup-plugin-ts": "^3.0.2",
45
45
  "ts-jest": "^29.0.5",
46
46
  "typescript": "^4.7.4",
47
- "@tarojs/runtime": "3.6.29",
48
- "@tarojs/taro": "3.6.29",
49
- "@tarojs/shared": "3.6.29"
47
+ "@tarojs/runtime": "3.6.31-canary.0",
48
+ "@tarojs/taro": "3.6.31-canary.0",
49
+ "@tarojs/shared": "3.6.31-canary.0"
50
50
  },
51
51
  "peerDependencies": {
52
- "@tarojs/runtime": "3.6.29",
53
- "@tarojs/taro": "3.6.29",
54
- "@tarojs/shared": "3.6.29"
52
+ "@tarojs/runtime": "3.6.31-canary.0",
53
+ "@tarojs/taro": "3.6.31-canary.0",
54
+ "@tarojs/shared": "3.6.31-canary.0"
55
55
  },
56
56
  "scripts": {
57
57
  "prebuild": "pnpm run clean",