@tarojs/router 3.6.29 → 3.6.31-alpha.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;
@@ -44,7 +45,7 @@ body {
44
45
  /**
45
46
  * 插入路由相关样式
46
47
  */
47
- function loadRouterStyle(enableTabBar, enableWindowScroll) {
48
+ function loadRouterStyle(enableTabBar, enableWindowScroll, enhanceAnimation) {
48
49
  const css = `
49
50
  .taro_router {
50
51
  position: relative;
@@ -72,11 +73,15 @@ ${enableTabBar ? `
72
73
  }
73
74
 
74
75
  ` : ''}
75
- .taro_page_shade:has(+.taro_page_stationed),
76
+ ${enhanceAnimation
77
+ ? `.taro_page_shade:has(+.taro_page_stationed),
76
78
  .taro_page_shade.taro_tabbar_page,
77
79
  .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child):has(+.taro_page_stationed) {
78
80
  display: none;
79
- }
81
+ }` : ` .taro_page_shade,
82
+ .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child) {
83
+ display: none;
84
+ }`}
80
85
  `;
81
86
  addStyle(css);
82
87
  }
@@ -142,7 +147,7 @@ function loadNavigationBarStyle() {
142
147
  to {
143
148
  transform: rotate(360deg);
144
149
  }
145
- }
150
+ }
146
151
 
147
152
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
148
153
  display: none;
@@ -535,13 +540,14 @@ function processNavigateUrl(option) {
535
540
  const parts = routesAlias.getOrigin(exports.history.location.pathname).split('/');
536
541
  parts.pop();
537
542
  pathPieces.pathname.split('/').forEach((item) => {
538
- if (item === '.') {
543
+ if (item === '.')
539
544
  return;
540
- }
541
545
  item === '..' ? parts.pop() : parts.push(item);
542
546
  });
543
547
  pathPieces.pathname = parts.join('/');
544
548
  }
549
+ // 确保是 / 开头的路径
550
+ pathPieces.pathname = runtime.addLeadingSlash(pathPieces.pathname);
545
551
  // 处理自定义路由
546
552
  pathPieces.pathname = routesAlias.getAlias(runtime.addLeadingSlash(pathPieces.pathname));
547
553
  // 处理 basename
@@ -569,20 +575,10 @@ function navigate(option, method) {
569
575
  });
570
576
  try {
571
577
  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
578
  const pathPieces = processNavigateUrl(option);
584
579
  const state = { timestamp: Date.now() };
585
580
  if (method === 'navigateTo') {
581
+ // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
586
582
  exports.history.push(pathPieces, state);
587
583
  }
588
584
  else if (method === 'redirectTo' || method === 'switchTab') {
@@ -975,7 +971,7 @@ class NavigationBarHandler {
975
971
  this.setNavigationLoading();
976
972
  }
977
973
  setCacheValue() {
978
- const currentPage = this.pageContext.currentPage;
974
+ const currentPage = this.pageContext.originPathname;
979
975
  if (typeof this.cache[currentPage] !== 'object') {
980
976
  this.cache[currentPage] = {};
981
977
  }
@@ -1006,7 +1002,7 @@ class NavigationBarHandler {
1006
1002
  var _a;
1007
1003
  if (!this.navigationBarElement)
1008
1004
  return;
1009
- const currentPage = this.pageContext.currentPage;
1005
+ const currentPage = this.pageContext.originPathname;
1010
1006
  let isShow;
1011
1007
  if (typeof show === 'boolean') {
1012
1008
  isShow = show;
@@ -1031,7 +1027,7 @@ class NavigationBarHandler {
1031
1027
  var _a, _b, _c;
1032
1028
  if (!this.navigationBarElement)
1033
1029
  return;
1034
- const currentPage = this.pageContext.currentPage;
1030
+ const currentPage = this.pageContext.originPathname;
1035
1031
  let color;
1036
1032
  if (typeof backgroundColor === 'string') {
1037
1033
  color = backgroundColor;
@@ -1055,7 +1051,7 @@ class NavigationBarHandler {
1055
1051
  var _a, _b, _c;
1056
1052
  if (!this.navigationBarElement)
1057
1053
  return;
1058
- const currentPage = this.pageContext.currentPage;
1054
+ const currentPage = this.pageContext.originPathname;
1059
1055
  let color;
1060
1056
  if (typeof fontColor === 'string') {
1061
1057
  color = fontColor;
@@ -1077,7 +1073,7 @@ class NavigationBarHandler {
1077
1073
  }
1078
1074
  setTitle(title) {
1079
1075
  var _a, _b, _c;
1080
- const currentPage = this.pageContext.currentPage;
1076
+ const currentPage = this.pageContext.originPathname;
1081
1077
  let proceedTitle;
1082
1078
  if (typeof title === 'string') {
1083
1079
  proceedTitle = title;
@@ -1192,14 +1188,14 @@ class PageHandler {
1192
1188
  }
1193
1189
  set pathname(p) { this.router.pathname = p; }
1194
1190
  get pathname() { return this.router.pathname; }
1191
+ // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
1192
+ get originPathname() { return routesAlias.getOrigin(runtime.addLeadingSlash(runtime.stripBasename(this.pathname, this.basename))); }
1195
1193
  get basename() { return this.router.basename || ''; }
1196
1194
  get pageConfig() {
1197
- const routePath = runtime.addLeadingSlash(runtime.stripBasename(this.pathname, this.basename));
1198
1195
  const homePage = runtime.addLeadingSlash(this.homePage);
1199
1196
  return this.routes.find(r => {
1200
- var _a;
1201
1197
  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));
1198
+ return [pagePath, homePage].includes(this.originPathname);
1203
1199
  });
1204
1200
  }
1205
1201
  isTabBar(pathname) {
@@ -1266,7 +1262,7 @@ class PageHandler {
1266
1262
  this.pathname = exports.history.location.pathname;
1267
1263
  // Note: 注入页面样式
1268
1264
  this.animation && loadAnimateStyle(this.animationDuration);
1269
- loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll);
1265
+ loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll, this.router.enhanceAnimation);
1270
1266
  }
1271
1267
  onReady(page, onLoad = true) {
1272
1268
  var _a;
@@ -1390,7 +1386,7 @@ class PageHandler {
1390
1386
  }
1391
1387
  }
1392
1388
  hide(page, animation = false) {
1393
- var _a, _b, _c, _d, _e, _f, _g;
1389
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1394
1390
  if (!page)
1395
1391
  return;
1396
1392
  // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
@@ -1415,6 +1411,7 @@ class PageHandler {
1415
1411
  this.hideTimer = null;
1416
1412
  (_g = (_f = (_e = this.lastHidePage) === null || _e === void 0 ? void 0 : _e.classList) === null || _f === void 0 ? void 0 : _f.add) === null || _g === void 0 ? void 0 : _g.call(_f, 'taro_page_shade');
1417
1413
  }
1414
+ (_h = page.onHide) === null || _h === void 0 ? void 0 : _h.call(page);
1418
1415
  pageEl.classList.add('taro_page_shade');
1419
1416
  this.lastHidePage = pageEl;
1420
1417
  }
@@ -1488,6 +1485,10 @@ function createRouter(history$1, app, config, framework) {
1488
1485
  }
1489
1486
  RouterConfig.config = config;
1490
1487
  const handler = new PageHandler(config, history$1);
1488
+ // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
1489
+ // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
1490
+ // 所以需要加一个锁来应对这个情况
1491
+ const pageLock = {};
1491
1492
  routesAlias.set(handler.router.customRoutes);
1492
1493
  const basename = handler.router.basename;
1493
1494
  const routes = handler.routes.map(route => {
@@ -1511,24 +1512,30 @@ function createRouter(history$1, app, config, framework) {
1511
1512
  app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
1512
1513
  const render = ({ location, action }) => tslib.__awaiter(this, void 0, void 0, function* () {
1513
1514
  var _c, _d, _e, _f, _g, _h, _j, _k;
1514
- handler.pathname = decodeURI(location.pathname);
1515
+ // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
1516
+ const currentPathname = decodeURI(location.pathname);
1515
1517
  if ((_c = window.__taroAppConfig) === null || _c === void 0 ? void 0 : _c.usingWindowScroll)
1516
1518
  window.scrollTo(0, 0);
1517
1519
  runtime.eventCenter.trigger('__taroRouterChange', {
1518
1520
  toLocation: {
1519
- path: handler.pathname
1521
+ path: currentPathname
1520
1522
  }
1521
1523
  });
1522
- let element, params;
1524
+ let element, context, params;
1525
+ const routerPath = handler.router.forcePath || currentPathname;
1526
+ pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
1527
+ const currentLock = pageLock[routerPath];
1528
+ let postLock;
1523
1529
  try {
1524
- const result = yield router.resolve(handler.router.forcePath || handler.pathname);
1525
- [element, , params] = yield Promise.all(result);
1530
+ const result = yield router.resolve(routerPath);
1531
+ [element, context, params] = yield Promise.all(result);
1532
+ postLock = pageLock[routerPath];
1526
1533
  }
1527
1534
  catch (error) {
1528
1535
  if (error.status === 404) {
1529
1536
  const notFoundEvent = {
1530
1537
  isEntryPage: stacks.length === 0,
1531
- path: handler.pathname,
1538
+ path: currentPathname,
1532
1539
  query: handler.getQuery(createStampId()),
1533
1540
  };
1534
1541
  (_d = app.onPageNotFound) === null || _d === void 0 ? void 0 : _d.call(app, notFoundEvent);
@@ -1542,9 +1549,12 @@ function createRouter(history$1, app, config, framework) {
1542
1549
  throw error;
1543
1550
  }
1544
1551
  }
1545
- if (!element)
1552
+ if (!element || currentLock !== postLock)
1546
1553
  return;
1547
- const pageConfig = handler.pageConfig;
1554
+ // Note: 异步结束后,在设置 handler.pathname
1555
+ // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
1556
+ handler.pathname = context.pathname;
1557
+ const { pathname, pageConfig } = handler;
1548
1558
  let enablePullDownRefresh = ((_e = config === null || config === void 0 ? void 0 : config.window) === null || _e === void 0 ? void 0 : _e.enablePullDownRefresh) || false;
1549
1559
  let navigationStyle = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.navigationStyle) || 'default';
1550
1560
  let navigationBarTextStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationBarTextStyle) || 'white';
@@ -1565,7 +1575,6 @@ function createRouter(history$1, app, config, framework) {
1565
1575
  }
1566
1576
  runtime.eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
1567
1577
  const currentPage = runtime.Current.page;
1568
- const pathname = handler.pathname;
1569
1578
  const methodName = (_j = stacks.method) !== null && _j !== void 0 ? _j : '';
1570
1579
  const cacheTabs = stacks.getTabs();
1571
1580
  let shouldLoad = false;
@@ -1581,7 +1590,7 @@ function createRouter(history$1, app, config, framework) {
1581
1590
  }
1582
1591
  shouldLoad = true;
1583
1592
  }
1584
- else if (currentPage && handler.isTabBar(handler.pathname)) {
1593
+ else if (currentPage && handler.isTabBar(pathname)) {
1585
1594
  if (handler.isSamePage(currentPage))
1586
1595
  return;
1587
1596
  if (handler.isTabBar(currentPage.path)) {
@@ -1599,8 +1608,8 @@ function createRouter(history$1, app, config, framework) {
1599
1608
  handler.unload(currentPage, stacks.length, true);
1600
1609
  }
1601
1610
  }
1602
- if (cacheTabs[handler.pathname]) {
1603
- stacks.popTab(handler.pathname);
1611
+ if (cacheTabs[pathname]) {
1612
+ stacks.popTab(pathname);
1604
1613
  return handler.show(stacks.getItem(0), pageConfig, 0);
1605
1614
  }
1606
1615
  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;
@@ -43,7 +44,7 @@ body {
43
44
  /**
44
45
  * 插入路由相关样式
45
46
  */
46
- function loadRouterStyle(enableTabBar, enableWindowScroll) {
47
+ function loadRouterStyle(enableTabBar, enableWindowScroll, enhanceAnimation) {
47
48
  const css = `
48
49
  .taro_router {
49
50
  position: relative;
@@ -71,11 +72,15 @@ ${enableTabBar ? `
71
72
  }
72
73
 
73
74
  ` : ''}
74
- .taro_page_shade:has(+.taro_page_stationed),
75
+ ${enhanceAnimation
76
+ ? `.taro_page_shade:has(+.taro_page_stationed),
75
77
  .taro_page_shade.taro_tabbar_page,
76
78
  .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child):has(+.taro_page_stationed) {
77
79
  display: none;
78
- }
80
+ }` : ` .taro_page_shade,
81
+ .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child) {
82
+ display: none;
83
+ }`}
79
84
  `;
80
85
  addStyle(css);
81
86
  }
@@ -141,7 +146,7 @@ function loadNavigationBarStyle() {
141
146
  to {
142
147
  transform: rotate(360deg);
143
148
  }
144
- }
149
+ }
145
150
 
146
151
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
147
152
  display: none;
@@ -534,13 +539,14 @@ function processNavigateUrl(option) {
534
539
  const parts = routesAlias.getOrigin(history.location.pathname).split('/');
535
540
  parts.pop();
536
541
  pathPieces.pathname.split('/').forEach((item) => {
537
- if (item === '.') {
542
+ if (item === '.')
538
543
  return;
539
- }
540
544
  item === '..' ? parts.pop() : parts.push(item);
541
545
  });
542
546
  pathPieces.pathname = parts.join('/');
543
547
  }
548
+ // 确保是 / 开头的路径
549
+ pathPieces.pathname = addLeadingSlash(pathPieces.pathname);
544
550
  // 处理自定义路由
545
551
  pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
546
552
  // 处理 basename
@@ -568,20 +574,10 @@ function navigate(option, method) {
568
574
  });
569
575
  try {
570
576
  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
577
  const pathPieces = processNavigateUrl(option);
583
578
  const state = { timestamp: Date.now() };
584
579
  if (method === 'navigateTo') {
580
+ // Note: 由于 spa 会针对弱网情况下,短时间内多次跳转同一个页面跳转加了锁,后续如果有用户反馈返回无效,那可能是这个问题
585
581
  history.push(pathPieces, state);
586
582
  }
587
583
  else if (method === 'redirectTo' || method === 'switchTab') {
@@ -974,7 +970,7 @@ class NavigationBarHandler {
974
970
  this.setNavigationLoading();
975
971
  }
976
972
  setCacheValue() {
977
- const currentPage = this.pageContext.currentPage;
973
+ const currentPage = this.pageContext.originPathname;
978
974
  if (typeof this.cache[currentPage] !== 'object') {
979
975
  this.cache[currentPage] = {};
980
976
  }
@@ -1005,7 +1001,7 @@ class NavigationBarHandler {
1005
1001
  var _a;
1006
1002
  if (!this.navigationBarElement)
1007
1003
  return;
1008
- const currentPage = this.pageContext.currentPage;
1004
+ const currentPage = this.pageContext.originPathname;
1009
1005
  let isShow;
1010
1006
  if (typeof show === 'boolean') {
1011
1007
  isShow = show;
@@ -1030,7 +1026,7 @@ class NavigationBarHandler {
1030
1026
  var _a, _b, _c;
1031
1027
  if (!this.navigationBarElement)
1032
1028
  return;
1033
- const currentPage = this.pageContext.currentPage;
1029
+ const currentPage = this.pageContext.originPathname;
1034
1030
  let color;
1035
1031
  if (typeof backgroundColor === 'string') {
1036
1032
  color = backgroundColor;
@@ -1054,7 +1050,7 @@ class NavigationBarHandler {
1054
1050
  var _a, _b, _c;
1055
1051
  if (!this.navigationBarElement)
1056
1052
  return;
1057
- const currentPage = this.pageContext.currentPage;
1053
+ const currentPage = this.pageContext.originPathname;
1058
1054
  let color;
1059
1055
  if (typeof fontColor === 'string') {
1060
1056
  color = fontColor;
@@ -1076,7 +1072,7 @@ class NavigationBarHandler {
1076
1072
  }
1077
1073
  setTitle(title) {
1078
1074
  var _a, _b, _c;
1079
- const currentPage = this.pageContext.currentPage;
1075
+ const currentPage = this.pageContext.originPathname;
1080
1076
  let proceedTitle;
1081
1077
  if (typeof title === 'string') {
1082
1078
  proceedTitle = title;
@@ -1191,14 +1187,14 @@ class PageHandler {
1191
1187
  }
1192
1188
  set pathname(p) { this.router.pathname = p; }
1193
1189
  get pathname() { return this.router.pathname; }
1190
+ // Note: 把 pathname 转换为原始路径,主要是处理 customRoutes 和 basename
1191
+ get originPathname() { return routesAlias.getOrigin(addLeadingSlash(stripBasename(this.pathname, this.basename))); }
1194
1192
  get basename() { return this.router.basename || ''; }
1195
1193
  get pageConfig() {
1196
- const routePath = addLeadingSlash(stripBasename(this.pathname, this.basename));
1197
1194
  const homePage = addLeadingSlash(this.homePage);
1198
1195
  return this.routes.find(r => {
1199
- var _a;
1200
1196
  const pagePath = addLeadingSlash(r.path);
1201
- return [pagePath, homePage].includes(routePath) || ((_a = routesAlias.getConfig(pagePath)) === null || _a === void 0 ? void 0 : _a.includes(routePath));
1197
+ return [pagePath, homePage].includes(this.originPathname);
1202
1198
  });
1203
1199
  }
1204
1200
  isTabBar(pathname) {
@@ -1265,7 +1261,7 @@ class PageHandler {
1265
1261
  this.pathname = history.location.pathname;
1266
1262
  // Note: 注入页面样式
1267
1263
  this.animation && loadAnimateStyle(this.animationDuration);
1268
- loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll);
1264
+ loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll, this.router.enhanceAnimation);
1269
1265
  }
1270
1266
  onReady(page, onLoad = true) {
1271
1267
  var _a;
@@ -1389,7 +1385,7 @@ class PageHandler {
1389
1385
  }
1390
1386
  }
1391
1387
  hide(page, animation = false) {
1392
- var _a, _b, _c, _d, _e, _f, _g;
1388
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1393
1389
  if (!page)
1394
1390
  return;
1395
1391
  // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
@@ -1414,6 +1410,7 @@ class PageHandler {
1414
1410
  this.hideTimer = null;
1415
1411
  (_g = (_f = (_e = this.lastHidePage) === null || _e === void 0 ? void 0 : _e.classList) === null || _f === void 0 ? void 0 : _f.add) === null || _g === void 0 ? void 0 : _g.call(_f, 'taro_page_shade');
1416
1412
  }
1413
+ (_h = page.onHide) === null || _h === void 0 ? void 0 : _h.call(page);
1417
1414
  pageEl.classList.add('taro_page_shade');
1418
1415
  this.lastHidePage = pageEl;
1419
1416
  }
@@ -1487,6 +1484,10 @@ function createRouter(history, app, config, framework) {
1487
1484
  }
1488
1485
  RouterConfig.config = config;
1489
1486
  const handler = new PageHandler(config, history);
1487
+ // Note: 弱网情况下,快速切换 tab,会造成同个页面实例被多次挂在到页面上,原因是资源请求是异步的,短时间内发起多个请求,
1488
+ // 会在资源加载完成后,同时走到挂载的逻辑,造成 pageStampId 更新不及时,两个 page 的Id 相同,后面很多操作是通过 getElementById 来进行的
1489
+ // 所以需要加一个锁来应对这个情况
1490
+ const pageLock = {};
1490
1491
  routesAlias.set(handler.router.customRoutes);
1491
1492
  const basename = handler.router.basename;
1492
1493
  const routes = handler.routes.map(route => {
@@ -1510,24 +1511,30 @@ function createRouter(history, app, config, framework) {
1510
1511
  app.onError && window.addEventListener('error', e => { var _a; return (_a = app.onError) === null || _a === void 0 ? void 0 : _a.call(app, e.message); });
1511
1512
  const render = ({ location, action }) => __awaiter(this, void 0, void 0, function* () {
1512
1513
  var _c, _d, _e, _f, _g, _h, _j, _k;
1513
- handler.pathname = decodeURI(location.pathname);
1514
+ // Note: 由于下面有异步加载操作 先不要在这里去设置 handler.pathname
1515
+ const currentPathname = decodeURI(location.pathname);
1514
1516
  if ((_c = window.__taroAppConfig) === null || _c === void 0 ? void 0 : _c.usingWindowScroll)
1515
1517
  window.scrollTo(0, 0);
1516
1518
  eventCenter.trigger('__taroRouterChange', {
1517
1519
  toLocation: {
1518
- path: handler.pathname
1520
+ path: currentPathname
1519
1521
  }
1520
1522
  });
1521
- let element, params;
1523
+ let element, context, params;
1524
+ const routerPath = handler.router.forcePath || currentPathname;
1525
+ pageLock[routerPath] = typeof pageLock[routerPath] === 'number' ? pageLock[routerPath] + 1 : 1;
1526
+ const currentLock = pageLock[routerPath];
1527
+ let postLock;
1522
1528
  try {
1523
- const result = yield router.resolve(handler.router.forcePath || handler.pathname);
1524
- [element, , params] = yield Promise.all(result);
1529
+ const result = yield router.resolve(routerPath);
1530
+ [element, context, params] = yield Promise.all(result);
1531
+ postLock = pageLock[routerPath];
1525
1532
  }
1526
1533
  catch (error) {
1527
1534
  if (error.status === 404) {
1528
1535
  const notFoundEvent = {
1529
1536
  isEntryPage: stacks.length === 0,
1530
- path: handler.pathname,
1537
+ path: currentPathname,
1531
1538
  query: handler.getQuery(createStampId()),
1532
1539
  };
1533
1540
  (_d = app.onPageNotFound) === null || _d === void 0 ? void 0 : _d.call(app, notFoundEvent);
@@ -1541,9 +1548,12 @@ function createRouter(history, app, config, framework) {
1541
1548
  throw error;
1542
1549
  }
1543
1550
  }
1544
- if (!element)
1551
+ if (!element || currentLock !== postLock)
1545
1552
  return;
1546
- const pageConfig = handler.pageConfig;
1553
+ // Note: 异步结束后,在设置 handler.pathname
1554
+ // context.pathname 在 universal-router 被处理过了,是发起资源请求的时候传入的 pathname,即 await router.resolve(routerPath) 这个 routerPath
1555
+ handler.pathname = context.pathname;
1556
+ const { pathname, pageConfig } = handler;
1547
1557
  let enablePullDownRefresh = ((_e = config === null || config === void 0 ? void 0 : config.window) === null || _e === void 0 ? void 0 : _e.enablePullDownRefresh) || false;
1548
1558
  let navigationStyle = ((_f = config === null || config === void 0 ? void 0 : config.window) === null || _f === void 0 ? void 0 : _f.navigationStyle) || 'default';
1549
1559
  let navigationBarTextStyle = ((_g = config === null || config === void 0 ? void 0 : config.window) === null || _g === void 0 ? void 0 : _g.navigationBarTextStyle) || 'white';
@@ -1564,7 +1574,6 @@ function createRouter(history, app, config, framework) {
1564
1574
  }
1565
1575
  eventCenter.trigger('__taroSetNavigationStyle', navigationStyle, navigationBarTextStyle, navigationBarBackgroundColor);
1566
1576
  const currentPage = Current.page;
1567
- const pathname = handler.pathname;
1568
1577
  const methodName = (_j = stacks.method) !== null && _j !== void 0 ? _j : '';
1569
1578
  const cacheTabs = stacks.getTabs();
1570
1579
  let shouldLoad = false;
@@ -1580,7 +1589,7 @@ function createRouter(history, app, config, framework) {
1580
1589
  }
1581
1590
  shouldLoad = true;
1582
1591
  }
1583
- else if (currentPage && handler.isTabBar(handler.pathname)) {
1592
+ else if (currentPage && handler.isTabBar(pathname)) {
1584
1593
  if (handler.isSamePage(currentPage))
1585
1594
  return;
1586
1595
  if (handler.isTabBar(currentPage.path)) {
@@ -1598,8 +1607,8 @@ function createRouter(history, app, config, framework) {
1598
1607
  handler.unload(currentPage, stacks.length, true);
1599
1608
  }
1600
1609
  }
1601
- if (cacheTabs[handler.pathname]) {
1602
- stacks.popTab(handler.pathname);
1610
+ if (cacheTabs[pathname]) {
1611
+ stacks.popTab(pathname);
1603
1612
  return handler.show(stacks.getItem(0), pageConfig, 0);
1604
1613
  }
1605
1614
  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) {
@@ -123,7 +123,7 @@ class PageHandler {
123
123
  this.pathname = history.location.pathname;
124
124
  // Note: 注入页面样式
125
125
  this.animation && loadAnimateStyle(this.animationDuration);
126
- loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll);
126
+ loadRouterStyle(this.tabBarList.length > 1, this.usingWindowScroll, this.router.enhanceAnimation);
127
127
  }
128
128
  onReady(page, onLoad = true) {
129
129
  var _a;
@@ -247,7 +247,7 @@ class PageHandler {
247
247
  }
248
248
  }
249
249
  hide(page, animation = false) {
250
- var _a, _b, _c, _d, _e, _f, _g;
250
+ var _a, _b, _c, _d, _e, _f, _g, _h;
251
251
  if (!page)
252
252
  return;
253
253
  // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
@@ -272,6 +272,7 @@ class PageHandler {
272
272
  this.hideTimer = null;
273
273
  (_g = (_f = (_e = this.lastHidePage) === null || _e === void 0 ? void 0 : _e.classList) === null || _f === void 0 ? void 0 : _f.add) === null || _g === void 0 ? void 0 : _g.call(_f, 'taro_page_shade');
274
274
  }
275
+ (_h = page.onHide) === null || _h === void 0 ? void 0 : _h.call(page);
275
276
  pageEl.classList.add('taro_page_shade');
276
277
  this.lastHidePage = pageEl;
277
278
  }
@@ -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.d.ts CHANGED
@@ -5,7 +5,7 @@ declare function loadAnimateStyle(ms?: number): void;
5
5
  /**
6
6
  * 插入路由相关样式
7
7
  */
8
- declare function loadRouterStyle(enableTabBar: boolean, enableWindowScroll: boolean): void;
8
+ declare function loadRouterStyle(enableTabBar: boolean, enableWindowScroll: boolean, enhanceAnimation?: boolean): void;
9
9
  /**
10
10
  * 插入导航栏相关的样式
11
11
  */
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;
@@ -33,7 +34,7 @@ body {
33
34
  /**
34
35
  * 插入路由相关样式
35
36
  */
36
- function loadRouterStyle(enableTabBar, enableWindowScroll) {
37
+ function loadRouterStyle(enableTabBar, enableWindowScroll, enhanceAnimation) {
37
38
  const css = `
38
39
  .taro_router {
39
40
  position: relative;
@@ -61,11 +62,15 @@ ${enableTabBar ? `
61
62
  }
62
63
 
63
64
  ` : ''}
64
- .taro_page_shade:has(+.taro_page_stationed),
65
+ ${enhanceAnimation
66
+ ? `.taro_page_shade:has(+.taro_page_stationed),
65
67
  .taro_page_shade.taro_tabbar_page,
66
68
  .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child):has(+.taro_page_stationed) {
67
69
  display: none;
68
- }
70
+ }` : ` .taro_page_shade,
71
+ .taro_router > .taro_page.taro_page_show.taro_page_stationed:not(.taro_page_shade):not(.taro_tabbar_page):not(:last-child) {
72
+ display: none;
73
+ }`}
69
74
  `;
70
75
  addStyle(css);
71
76
  }
@@ -131,7 +136,7 @@ function loadNavigationBarStyle() {
131
136
  to {
132
137
  transform: rotate(360deg);
133
138
  }
134
- }
139
+ }
135
140
 
136
141
  .taro-navigation-bar-no-icon > .taro-navigation-bar-home {
137
142
  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-alpha.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-alpha.0",
48
+ "@tarojs/shared": "3.6.31-alpha.0",
49
+ "@tarojs/taro": "3.6.31-alpha.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-alpha.0",
53
+ "@tarojs/taro": "3.6.31-alpha.0",
54
+ "@tarojs/shared": "3.6.31-alpha.0"
55
55
  },
56
56
  "scripts": {
57
57
  "prebuild": "pnpm run clean",
package/types/router.d.ts CHANGED
@@ -12,6 +12,8 @@ export interface Router {
12
12
  customRoutes?: Record<string, string | string[]>
13
13
  pathname: string
14
14
  forcePath?: string
15
+ /** 加上这个参数,可以解决返回页面的时候白屏的问题,但是某些不支持 :has() 选择器的浏览器会有问题 */
16
+ enhanceAnimation?: boolean
15
17
  }
16
18
 
17
19
  export interface SpaRouterConfig extends AppConfig {