@tarojs/router 3.3.13 → 3.3.17

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.
@@ -1,4 +1,5 @@
1
- import { container, SERVICE_IDENTIFIER, eventCenter, Current, stringify, createPageConfig, requestAnimationFrame } from '@tarojs/runtime';
1
+ import { requestAnimationFrame, container, SERVICE_IDENTIFIER, eventCenter, Current, createPageConfig, stringify } from '@tarojs/runtime';
2
+ import { initTabBarApis } from '@tarojs/taro';
2
3
 
3
4
  function _extends() {
4
5
  _extends = Object.assign || function (target) {
@@ -47,55 +48,141 @@ function setHistoryMode(mode, base = '/') {
47
48
  }
48
49
  function prependBasename(url = '') {
49
50
  return basename.replace(/\/$/, '') + '/' + url.replace(/^\//, '');
50
- }
51
-
52
- const stacks = [];
51
+ }
52
+ const hasBasename = (path, prefix) => new RegExp('^' + prefix + '(\\/|\\?|#|$)', 'i').test(path);
53
+ const stripBasename = (path, prefix) => hasBasename(path, prefix) ? path.substr(prefix.length) : path;
53
54
 
54
- let routesAlias = {};
55
- function setRoutesAlias(alias) {
56
- routesAlias = alias;
55
+ class Stacks {
56
+ constructor() {
57
+ this.stacks = [];
58
+ this.backDelta = 0;
59
+ }
60
+ set delta(delta) {
61
+ if (delta > 0) {
62
+ this.backDelta = delta;
63
+ }
64
+ else {
65
+ --this.backDelta;
66
+ }
67
+ }
68
+ get length() {
69
+ return this.stacks.length;
70
+ }
71
+ get last() {
72
+ return this.stacks[this.length - 1];
73
+ }
74
+ get() {
75
+ return this.stacks;
76
+ }
77
+ getItem(index) {
78
+ return this.stacks[index];
79
+ }
80
+ getLastIndex(pathname) {
81
+ const list = [...this.stacks].reverse();
82
+ return list.findIndex((page, i) => { var _a; return i !== 0 && ((_a = page.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname; });
83
+ }
84
+ getDelta(pathname) {
85
+ if (this.backDelta >= 1) {
86
+ return this.backDelta;
87
+ }
88
+ // NOTE: 此处为了修复浏览器后退多级页面,在大量重复路由状况下可能出现判断错误的情况 (增强判断能力只能考虑在 query 中新增参数来判断,暂时搁置)
89
+ return this.getLastIndex(pathname) || 1;
90
+ }
91
+ getPrevIndex(pathname) {
92
+ const lastIndex = this.getLastIndex(pathname);
93
+ if (lastIndex < 0) {
94
+ return -1;
95
+ }
96
+ return this.length - 1 - lastIndex;
97
+ }
98
+ pop() {
99
+ return this.stacks.pop();
100
+ }
101
+ push(page) {
102
+ return this.stacks.push(page);
103
+ }
57
104
  }
105
+ const stacks = new Stacks();
106
+
58
107
  function addLeadingSlash(path) {
59
108
  if (path == null) {
60
109
  return '';
61
110
  }
62
111
  return path.charAt(0) === '/' ? path : '/' + path;
63
112
  }
64
- // 解决navigateBack调用delta>1时,路由栈异常问题
65
- // 比如:A->B->C,navigateBack({delta: 2}),此时路由栈中还存在B页面
66
- // 原因:主要是由于一次性退出多层级页面时,此action只会执行一次,此处进行手动处理
67
- let historyBackDelta = 1;
68
- function setHistoryBackDelta(delta) {
69
- historyBackDelta = delta;
70
- }
71
- // eslint-disable-next-line @typescript-eslint/ban-types
72
- const throttle = (fn, threshold) => {
73
- let lastTime = 0;
74
- return function () {
75
- const now = Date.now();
76
- if (now - lastTime > threshold) {
77
- fn.apply(this, arguments);
78
- lastTime = now;
113
+ class RoutesAlias {
114
+ constructor() {
115
+ this.conf = [];
116
+ this.getConfig = (url) => {
117
+ const customRoute = this.conf.filter((arr) => {
118
+ return arr.includes(url);
119
+ });
120
+ return customRoute[0];
121
+ };
122
+ this.getOrigin = (url) => {
123
+ var _a;
124
+ return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[0]) || url;
125
+ };
126
+ this.getAlias = (url) => {
127
+ var _a;
128
+ return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[1]) || url;
129
+ };
130
+ this.getAll = (url) => {
131
+ return this.conf.filter((arr) => {
132
+ return arr.includes(url);
133
+ }).reduce((p, a) => {
134
+ p.push(a[1]);
135
+ return p;
136
+ }, [url]);
137
+ };
138
+ }
139
+ set(customRoutes = {}) {
140
+ for (let key in customRoutes) {
141
+ const path = customRoutes[key];
142
+ key = addLeadingSlash(key);
143
+ if (typeof path === 'string') {
144
+ this.conf.push([key, addLeadingSlash(path)]);
145
+ }
146
+ else if ((path === null || path === void 0 ? void 0 : path.length) > 0) {
147
+ this.conf.push(...path.map(p => [key, addLeadingSlash(p)]));
148
+ }
79
149
  }
80
- };
81
- };
82
- const stripBasename = (path, basename) => path.startsWith(basename) ? path.replace(basename, '') : path;
150
+ }
151
+ }
152
+ const routesAlias = new RoutesAlias();
83
153
  const isTabBar = (config) => {
84
154
  var _a, _b;
85
155
  const { customRoutes = {}, basename = '', pathname } = config.router;
86
156
  const routePath = stripBasename(pathname, basename);
87
- const pagePath = ((_a = Object.entries(customRoutes).find(([, target]) => target === routePath)) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
157
+ const pagePath = ((_a = Object.entries(customRoutes).find(([, target]) => {
158
+ if (typeof target === 'string') {
159
+ return target === routePath;
160
+ }
161
+ else if ((target === null || target === void 0 ? void 0 : target.length) > 0) {
162
+ return target.includes(routePath);
163
+ }
164
+ return false;
165
+ })) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
88
166
  return !!pagePath && (((_b = config.tabBar) === null || _b === void 0 ? void 0 : _b.list) || []).some(t => t.pagePath === pagePath);
89
167
  };
90
168
 
91
169
  function processNavigateUrl(option) {
170
+ var _a;
92
171
  const pathPieces = J(option.url);
93
172
  // 处理自定义路由
94
- Object.keys(routesAlias).forEach(key => {
95
- if (addLeadingSlash(key) === addLeadingSlash(pathPieces.pathname)) {
96
- pathPieces.pathname = routesAlias[key];
97
- }
98
- });
173
+ pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
174
+ // 处理相对路径
175
+ if ((_a = pathPieces === null || pathPieces === void 0 ? void 0 : pathPieces.pathname) === null || _a === void 0 ? void 0 : _a.includes('./')) {
176
+ const parts = history.location.pathname.split('/');
177
+ parts.pop();
178
+ pathPieces.pathname.split('/').forEach((item) => {
179
+ if (item === '.') {
180
+ return;
181
+ }
182
+ item === '..' ? parts.pop() : parts.push(item);
183
+ });
184
+ pathPieces.pathname = parts.join('/');
185
+ }
99
186
  // 处理 basename
100
187
  pathPieces.pathname = prependBasename(pathPieces.pathname);
101
188
  // hack fix history v5 bug: https://github.com/remix-run/history/issues/814
@@ -107,9 +194,10 @@ async function navigate(option, method) {
107
194
  return new Promise((resolve, reject) => {
108
195
  const { success, complete, fail } = option;
109
196
  const unListen = history.listen(() => {
110
- success === null || success === void 0 ? void 0 : success();
111
- complete === null || complete === void 0 ? void 0 : complete();
112
- resolve();
197
+ const res = { errMsg: `${method}: ok` };
198
+ success === null || success === void 0 ? void 0 : success(res);
199
+ complete === null || complete === void 0 ? void 0 : complete(res);
200
+ resolve(res);
113
201
  unListen();
114
202
  });
115
203
  try {
@@ -119,19 +207,24 @@ async function navigate(option, method) {
119
207
  if (method === 'navigateTo') {
120
208
  history.push(pathPieces, state);
121
209
  }
122
- else if (method === 'redirectTo') {
210
+ else if (method === 'redirectTo' || method === 'switchTab') {
211
+ history.replace(pathPieces, state);
212
+ }
213
+ else if (method === 'reLaunch') {
214
+ stacks.delta = stacks.length;
123
215
  history.replace(pathPieces, state);
124
216
  }
125
217
  }
126
218
  else if (method === 'navigateBack') {
127
- setHistoryBackDelta(option.delta);
219
+ stacks.delta = option.delta;
128
220
  history.go(-option.delta);
129
221
  }
130
222
  }
131
223
  catch (error) {
132
- fail === null || fail === void 0 ? void 0 : fail(error);
133
- complete === null || complete === void 0 ? void 0 : complete();
134
- reject(error);
224
+ const res = { errMsg: `${method}: fail ${error.message || error}` };
225
+ fail === null || fail === void 0 ? void 0 : fail(res);
226
+ complete === null || complete === void 0 ? void 0 : complete(res);
227
+ reject(res);
135
228
  }
136
229
  });
137
230
  }
@@ -148,15 +241,14 @@ function navigateBack(options = { delta: 1 }) {
148
241
  return navigate(options, 'navigateBack');
149
242
  }
150
243
  function switchTab(option) {
151
- // TODO: 清除掉所有的栈去目标页面
152
- return redirectTo(option);
244
+ return navigate(option, 'switchTab');
153
245
  }
154
246
  function reLaunch(option) {
155
- // TODO: 清除掉所有的栈去目标页面
156
- return redirectTo(option);
247
+ return navigate(option, 'reLaunch');
157
248
  }
158
249
  function getCurrentPages() {
159
- return stacks;
250
+ const pages = stacks.get();
251
+ return pages.map(e => (Object.assign(Object.assign({}, e), { route: e.path || '' })));
160
252
  }
161
253
 
162
254
  /**
@@ -802,18 +894,18 @@ var UniversalRouter = function () {
802
894
 
803
895
  UniversalRouter.pathToRegexp = pathToRegexp_1;
804
896
 
897
+ // @ts-nocheck
805
898
  function initTabbar(config) {
806
899
  if (config.tabBar == null) {
807
900
  return;
808
901
  }
809
902
  // TODO: 找到 tabbar 的类型
810
903
  const tabbar = document.createElement('taro-tabbar');
811
- const homePage = config.pages ? config.pages[0] : '';
904
+ const homePage = config.entryPagePath || (config.pages ? config.pages[0] : '');
812
905
  tabbar.conf = config.tabBar;
813
906
  tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
814
907
  const routerConfig = config.router;
815
908
  tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
816
- tabbar.conf.custom = !!routerConfig.customRoutes;
817
909
  if (routerConfig.customRoutes) {
818
910
  tabbar.conf.custom = true;
819
911
  tabbar.conf.customRoutes = routerConfig.customRoutes;
@@ -828,6 +920,7 @@ function initTabbar(config) {
828
920
  const container = document.getElementById('container');
829
921
  // eslint-disable-next-line no-unused-expressions
830
922
  container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
923
+ initTabBarApis(config);
831
924
  }
832
925
 
833
926
  const routerConfig = Object.create(null);
@@ -851,6 +944,58 @@ function init(config) {
851
944
  initTabbar(config);
852
945
  }
853
946
 
947
+ let pageScrollFn;
948
+ let pageDOM = window;
949
+ function bindPageScroll(page, config) {
950
+ pageDOM.removeEventListener('scroll', pageScrollFn);
951
+ pageDOM = getScrollContainer();
952
+ const distance = config.onReachBottomDistance || 50;
953
+ let isReachBottom = false;
954
+ pageScrollFn = function () {
955
+ page.onPageScroll && page.onPageScroll({
956
+ scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
957
+ });
958
+ if (isReachBottom && getOffset() > distance) {
959
+ isReachBottom = false;
960
+ }
961
+ if (page.onReachBottom &&
962
+ !isReachBottom &&
963
+ getOffset() < distance) {
964
+ isReachBottom = true;
965
+ page.onReachBottom();
966
+ }
967
+ };
968
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
969
+ }
970
+ window.addEventListener('DOMSubtreeModified', (e) => {
971
+ var _a;
972
+ // @ts-ignore
973
+ const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
974
+ if (className && /taro-tabbar__/.test(className)) {
975
+ pageDOM.removeEventListener('scroll', pageScrollFn);
976
+ pageDOM = getScrollContainer();
977
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
978
+ }
979
+ }, false);
980
+ function getScrollContainer() {
981
+ if (document.querySelector('.taro-tabbar__tabbar') === null) {
982
+ // 没设置tabbar
983
+ return window;
984
+ }
985
+ else {
986
+ // 有设置tabbar
987
+ return document.querySelector('.taro-tabbar__panel') || window;
988
+ }
989
+ }
990
+ function getOffset() {
991
+ if (pageDOM instanceof Window) {
992
+ return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
993
+ }
994
+ else {
995
+ return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
996
+ }
997
+ }
998
+
854
999
  function createCommonjsModule(fn, module) {
855
1000
  return module = { exports: {} }, fn(module, module.exports), module.exports;
856
1001
  }
@@ -1402,12 +1547,23 @@ var queryString_5 = queryString.stringifyUrl;
1402
1547
  var queryString_6 = queryString.pick;
1403
1548
  var queryString_7 = queryString.exclude;
1404
1549
 
1550
+ function getSearch() {
1551
+ let search = '?';
1552
+ if (routerConfig.router.mode === 'hash') {
1553
+ const idx = location.hash.indexOf('?');
1554
+ if (idx > -1) {
1555
+ search = location.hash.slice(idx);
1556
+ }
1557
+ }
1558
+ else {
1559
+ search = location.search;
1560
+ }
1561
+ return search.substr(1);
1562
+ }
1405
1563
  const qs = function (stamp = 0) {
1406
- const search = routerConfig.router.mode === 'hash'
1407
- ? location.hash.slice(routerConfig.router.pathname.length + 1)
1408
- : location.search;
1564
+ const search = getSearch();
1409
1565
  const query = search
1410
- ? queryString.parse(search.substr(1))
1566
+ ? queryString.parse(search)
1411
1567
  : {};
1412
1568
  if (stamp) {
1413
1569
  query.stamp = stamp.toString();
@@ -1415,95 +1571,13 @@ const qs = function (stamp = 0) {
1415
1571
  return query;
1416
1572
  };
1417
1573
 
1418
- let pageScrollFn;
1419
- let pageDOM = window;
1420
- function bindPageScroll(page, config) {
1421
- pageDOM.removeEventListener('scroll', pageScrollFn);
1422
- pageDOM = getScrollContainer();
1423
- const distance = config.onReachBottomDistance || 50;
1424
- let isReachBottom = false;
1425
- pageScrollFn = function () {
1426
- page.onPageScroll && page.onPageScroll({
1427
- scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
1428
- });
1429
- if (isReachBottom && getOffset() > distance) {
1430
- isReachBottom = false;
1431
- }
1432
- if (page.onReachBottom &&
1433
- !isReachBottom &&
1434
- getOffset() < distance) {
1435
- isReachBottom = true;
1436
- page.onReachBottom();
1437
- }
1438
- };
1439
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1440
- }
1441
- window.addEventListener('DOMSubtreeModified', (e) => {
1442
- var _a;
1443
- // @ts-ignore
1444
- const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
1445
- if (className && /taro-tabbar__/.test(className)) {
1446
- pageDOM.removeEventListener('scroll', pageScrollFn);
1447
- pageDOM = getScrollContainer();
1448
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1449
- }
1450
- }, false);
1451
- function getScrollContainer() {
1452
- if (document.querySelector('.taro-tabbar__tabbar') === null) {
1453
- // 没设置tabbar
1454
- return window;
1455
- }
1456
- else {
1457
- // 有设置tabbar
1458
- return document.querySelector('.taro-tabbar__panel') || window;
1459
- }
1460
- }
1461
- function getOffset() {
1462
- if (pageDOM instanceof Window) {
1463
- return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
1464
- }
1465
- else {
1466
- return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
1467
- }
1468
- }
1469
-
1470
1574
  /* eslint-disable dot-notation */
1471
- function hidePage(page) {
1472
- if (page != null) {
1473
- page.onHide();
1474
- const pageEl = document.getElementById(page.path);
1475
- if (pageEl) {
1476
- pageEl.style.display = 'none';
1477
- }
1478
- }
1479
- }
1480
- function showPage(page, pageConfig, stacksIndex = 0) {
1481
- if (page != null) {
1482
- page.onShow();
1483
- let pageEl = document.getElementById(page.path);
1484
- if (pageEl) {
1485
- pageEl.style.display = 'block';
1486
- }
1487
- else {
1488
- page.onLoad(qs(stacksIndex));
1489
- pageEl = document.getElementById(page.path);
1490
- pageOnReady(pageEl, page, false);
1491
- }
1492
- bindPageScroll(page, pageConfig || {});
1493
- }
1494
- }
1495
- function unloadPage(page) {
1496
- if (page != null) {
1497
- stacks.pop();
1498
- page.onUnload();
1499
- }
1500
- }
1501
- function pageOnReady(pageEl, page, onLoad = true) {
1502
- var _a;
1575
+ function pageOnReady(page, onLoad = true) {
1576
+ var _a, _b;
1577
+ const pageEl = document.getElementById(page.path);
1503
1578
  if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1504
1579
  const el = pageEl.firstElementChild;
1505
- // eslint-disable-next-line no-unused-expressions
1506
- (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el).then(() => {
1580
+ (_b = (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el)) === null || _b === void 0 ? void 0 : _b.then(() => {
1507
1581
  requestAnimationFrame(() => {
1508
1582
  page.onReady();
1509
1583
  pageEl['__isReady'] = true;
@@ -1512,42 +1586,75 @@ function pageOnReady(pageEl, page, onLoad = true) {
1512
1586
  onLoad && (pageEl['__page'] = page);
1513
1587
  }
1514
1588
  }
1515
- function loadPage(page, pageConfig, stacksIndex = 0) {
1516
- if (page !== null) {
1517
- let pageEl = document.getElementById(page.path);
1518
- if (pageEl) {
1519
- pageEl.style.display = 'block';
1520
- }
1521
- else {
1522
- page.onLoad(qs(stacksIndex), function () {
1523
- pageEl = document.getElementById(page.path);
1524
- pageOnReady(pageEl, page);
1525
- });
1526
- }
1527
- stacks.push(page);
1528
- page.onShow();
1529
- bindPageScroll(page, pageConfig || {});
1589
+ function loadPage(page, pageConfig = {}, stacksIndex = 0) {
1590
+ if (!page)
1591
+ return;
1592
+ const pageEl = document.getElementById(page.path);
1593
+ if (pageEl) {
1594
+ pageEl.style.display = 'block';
1595
+ }
1596
+ else {
1597
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, true));
1598
+ }
1599
+ stacks.push(page);
1600
+ page.onShow();
1601
+ bindPageScroll(page, pageConfig);
1602
+ }
1603
+ function unloadPage(page, delta = 1) {
1604
+ if (!page)
1605
+ return;
1606
+ stacks.delta = --delta;
1607
+ stacks.pop();
1608
+ page.onUnload();
1609
+ if (delta >= 1)
1610
+ unloadPage(stacks.last, delta);
1611
+ }
1612
+ function showPage(page, pageConfig = {}, stacksIndex = 0) {
1613
+ if (!page)
1614
+ return;
1615
+ page.onShow();
1616
+ const pageEl = document.getElementById(page.path);
1617
+ if (pageEl) {
1618
+ pageEl.style.display = 'block';
1530
1619
  }
1620
+ else {
1621
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, false));
1622
+ }
1623
+ bindPageScroll(page, pageConfig);
1531
1624
  }
1625
+ function hidePage(page) {
1626
+ if (!page)
1627
+ return;
1628
+ // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
1629
+ const pageEl = document.getElementById(page.path);
1630
+ if (pageEl) {
1631
+ pageEl.style.display = 'none';
1632
+ page.onHide();
1633
+ }
1634
+ else {
1635
+ setTimeout(() => hidePage(page), 0);
1636
+ }
1637
+ }
1638
+
1639
+ /* eslint-disable dot-notation */
1532
1640
  function createRouter(app, config, framework) {
1533
1641
  var _a;
1534
1642
  init(config);
1535
1643
  const routes = [];
1536
- const alias = (_a = config.router.customRoutes) !== null && _a !== void 0 ? _a : {};
1537
1644
  const runtimeHooks = container.get(SERVICE_IDENTIFIER.Hooks);
1538
- setRoutesAlias(alias);
1645
+ routesAlias.set(config.router.customRoutes);
1539
1646
  for (let i = 0; i < config.routes.length; i++) {
1540
1647
  const route = config.routes[i];
1541
1648
  const path = addLeadingSlash(route.path);
1542
1649
  routes.push({
1543
- path: alias[path] || path,
1650
+ path: routesAlias.getAll(path),
1544
1651
  action: route.load
1545
1652
  });
1546
1653
  }
1547
1654
  const basename = config.router.basename;
1548
1655
  const router = new UniversalRouter(routes, { baseUrl: basename || '' });
1549
1656
  app.onLaunch();
1550
- const render = throttle(async ({ location, action }) => {
1657
+ const render = async ({ location, action }) => {
1551
1658
  var _a, _b, _c, _d;
1552
1659
  routerConfig.router.pathname = location.pathname;
1553
1660
  let element;
@@ -1567,8 +1674,10 @@ function createRouter(app, config, framework) {
1567
1674
  if (!element)
1568
1675
  return;
1569
1676
  const pageConfig = config.routes.find(r => {
1677
+ var _a;
1570
1678
  const path = addLeadingSlash(r.path);
1571
- return path === location.pathname || alias[path] === location.pathname;
1679
+ const urlPath = stripBasename(location.pathname, routerConfig.router.basename);
1680
+ return path === urlPath || ((_a = routesAlias.getConfig(path)) === null || _a === void 0 ? void 0 : _a.includes(urlPath));
1572
1681
  });
1573
1682
  let enablePullDownRefresh = false;
1574
1683
  eventCenter.trigger('__taroRouterChange', {
@@ -1580,67 +1689,53 @@ function createRouter(app, config, framework) {
1580
1689
  document.title = (_b = pageConfig.navigationBarTitleText) !== null && _b !== void 0 ? _b : document.title;
1581
1690
  enablePullDownRefresh = pageConfig.enablePullDownRefresh;
1582
1691
  }
1692
+ const currentPage = Current.page;
1693
+ const pathname = location.pathname;
1583
1694
  let shouldLoad = false;
1584
1695
  if (action === 'POP') {
1585
- unloadPage(Current.page);
1586
- let delta = historyBackDelta;
1587
- while (delta-- > 1) {
1588
- unloadPage(stacks.slice(-1)[0]);
1589
- }
1590
- // 最终必须重置为 1
1591
- setHistoryBackDelta(1);
1592
- const prevIndex = stacks.reduceRight((p, s, i) => {
1593
- if (p !== 0)
1594
- return p;
1595
- else if (s.path === location.pathname + stringify(qs(i)))
1596
- return i;
1597
- else
1598
- return 0;
1599
- }, 0);
1600
- const prev = stacks[prevIndex];
1601
- if (prev) {
1602
- showPage(prev, pageConfig, prevIndex);
1696
+ // NOTE: 浏览器事件退后多次时,该事件只会被触发一次
1697
+ const prevIndex = stacks.getPrevIndex(pathname);
1698
+ const delta = stacks.getDelta(pathname);
1699
+ unloadPage(currentPage, delta);
1700
+ if (prevIndex > -1) {
1701
+ showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1603
1702
  }
1604
1703
  else {
1605
1704
  shouldLoad = true;
1606
1705
  }
1607
1706
  }
1608
1707
  else if (action === 'PUSH') {
1609
- hidePage(Current.page);
1708
+ hidePage(currentPage);
1610
1709
  shouldLoad = true;
1611
1710
  }
1612
1711
  else if (action === 'REPLACE') {
1613
1712
  if (isTabBar(config)) {
1614
- hidePage(Current.page);
1615
- const pathname = stripBasename(config.router.pathname, basename);
1616
- const prevIndex = stacks.findIndex((r) => {
1617
- var _a;
1618
- return ((_a = r.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname;
1619
- });
1713
+ hidePage(currentPage);
1714
+ const prevIndex = stacks.getPrevIndex(pathname);
1620
1715
  if (prevIndex > -1) {
1621
- // tabbar 页且之前出现过,直接复用
1622
- const prev = stacks[prevIndex];
1623
- return showPage(prev, pageConfig, prevIndex);
1716
+ // NOTE: tabbar 页且之前出现过,直接复用
1717
+ return showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1624
1718
  }
1625
1719
  }
1626
1720
  else {
1627
- unloadPage(Current.page);
1721
+ const delta = stacks.getDelta(pathname);
1722
+ // NOTE: 页面路由记录并不会清空,只是移除掉缓存的 stack 以及页面
1723
+ unloadPage(currentPage, delta);
1628
1724
  }
1629
1725
  shouldLoad = true;
1630
1726
  }
1631
- if (shouldLoad) {
1727
+ if (shouldLoad || stacks.length < 1) {
1632
1728
  const el = (_c = element.default) !== null && _c !== void 0 ? _c : element;
1633
1729
  const loadConfig = Object.assign({}, pageConfig);
1730
+ const stacksIndex = stacks.length;
1634
1731
  delete loadConfig['path'];
1635
1732
  delete loadConfig['load'];
1636
- const pathname = stripBasename(config.router.pathname, basename);
1637
- const routerIndex = stacks.length;
1638
- const page = createPageConfig(enablePullDownRefresh ? (_d = runtimeHooks.createPullDownComponent) === null || _d === void 0 ? void 0 : _d.call(runtimeHooks, el, location.pathname, framework, routerConfig.PullDownRefresh) : el, pathname + stringify(qs(routerIndex)), {}, loadConfig);
1639
- loadPage(page, pageConfig, routerIndex);
1733
+ const page = createPageConfig(enablePullDownRefresh ? (_d = runtimeHooks.createPullDownComponent) === null || _d === void 0 ? void 0 : _d.call(runtimeHooks, el, location.pathname, framework, routerConfig.PullDownRefresh) : el, pathname + stringify(qs(stacksIndex)), {}, loadConfig);
1734
+ return loadPage(page, pageConfig, stacksIndex);
1640
1735
  }
1641
- }, 500);
1736
+ };
1642
1737
  if (history.location.pathname === '/') {
1643
- history.replace(prependBasename(routes[0].path + history.location.search));
1738
+ history.replace(prependBasename((config.entryPagePath || ((_a = routes[0].path) === null || _a === void 0 ? void 0 : _a[0])) + history.location.search));
1644
1739
  }
1645
1740
  render({ location: history.location, action: r.Push });
1646
1741
  app.onShow(qs(stacks.length));