@tarojs/router 3.3.15 → 3.3.19

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 { requestAnimationFrame, container, SERVICE_IDENTIFIER, eventCenter, Current, createPageConfig, stringify } from '@tarojs/runtime';
1
+ import { Current, requestAnimationFrame, container, SERVICE_IDENTIFIER, eventCenter, createPageConfig, stringify } from '@tarojs/runtime';
2
+ import { initTabBarApis } from '@tarojs/taro';
2
3
 
3
4
  function _extends() {
4
5
  _extends = Object.assign || function (target) {
@@ -48,8 +49,8 @@ function setHistoryMode(mode, base = '/') {
48
49
  function prependBasename(url = '') {
49
50
  return basename.replace(/\/$/, '') + '/' + url.replace(/^\//, '');
50
51
  }
51
- const hasBasename = (path, prefix) => new RegExp('^' + prefix + '(\\/|\\?|#|$)', 'i').test(path);
52
- const stripBasename = (path, prefix) => hasBasename(path, prefix) ? path.substr(prefix.length) : path;
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
55
  class Stacks {
55
56
  constructor() {
@@ -60,9 +61,12 @@ class Stacks {
60
61
  if (delta > 0) {
61
62
  this.backDelta = delta;
62
63
  }
63
- else {
64
+ else if (this.backDelta > 0) {
64
65
  --this.backDelta;
65
66
  }
67
+ else {
68
+ this.backDelta = 0;
69
+ }
66
70
  }
67
71
  get length() {
68
72
  return this.stacks.length;
@@ -76,16 +80,24 @@ class Stacks {
76
80
  getItem(index) {
77
81
  return this.stacks[index];
78
82
  }
83
+ getLastIndex(pathname, stateWith = 1) {
84
+ const list = [...this.stacks].reverse();
85
+ return list.findIndex((page, i) => { var _a; return i >= stateWith && ((_a = page.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname; });
86
+ }
79
87
  getDelta(pathname) {
80
88
  if (this.backDelta >= 1) {
81
89
  return this.backDelta;
82
90
  }
91
+ const index = this.getLastIndex(pathname);
83
92
  // NOTE: 此处为了修复浏览器后退多级页面,在大量重复路由状况下可能出现判断错误的情况 (增强判断能力只能考虑在 query 中新增参数来判断,暂时搁置)
84
- const prevIndex = this.stacks.findIndex(r => { var _a; return ((_a = r.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname; });
85
- return this.length - 1 - prevIndex;
93
+ return index > 0 ? index : 1;
86
94
  }
87
- getPrevIndex(pathname) {
88
- return this.length - 1 - this.getDelta(pathname);
95
+ getPrevIndex(pathname, stateWith = 1) {
96
+ const lastIndex = this.getLastIndex(pathname, stateWith);
97
+ if (lastIndex < 0) {
98
+ return -1;
99
+ }
100
+ return this.length - 1 - lastIndex;
89
101
  }
90
102
  pop() {
91
103
  return this.stacks.pop();
@@ -96,33 +108,58 @@ class Stacks {
96
108
  }
97
109
  const stacks = new Stacks();
98
110
 
99
- let routesAlias = {};
100
- function setRoutesAlias(alias) {
101
- routesAlias = alias;
102
- }
103
111
  function addLeadingSlash(path) {
104
112
  if (path == null) {
105
113
  return '';
106
114
  }
107
115
  return path.charAt(0) === '/' ? path : '/' + path;
108
116
  }
109
- const isTabBar = (config) => {
110
- var _a, _b;
111
- const { customRoutes = {}, basename = '', pathname } = config.router;
112
- const routePath = stripBasename(pathname, basename);
113
- const pagePath = ((_a = Object.entries(customRoutes).find(([, target]) => target === routePath)) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
114
- return !!pagePath && (((_b = config.tabBar) === null || _b === void 0 ? void 0 : _b.list) || []).some(t => t.pagePath === pagePath);
115
- };
117
+ class RoutesAlias {
118
+ constructor() {
119
+ this.conf = [];
120
+ this.getConfig = (url = '') => {
121
+ const customRoute = this.conf.filter((arr) => {
122
+ return arr.includes(url);
123
+ });
124
+ return customRoute[0];
125
+ };
126
+ this.getOrigin = (url = '') => {
127
+ var _a;
128
+ return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[0]) || url;
129
+ };
130
+ this.getAlias = (url = '') => {
131
+ var _a;
132
+ return ((_a = this.getConfig(url)) === null || _a === void 0 ? void 0 : _a[1]) || url;
133
+ };
134
+ this.getAll = (url = '') => {
135
+ return this.conf.filter((arr) => {
136
+ return arr.includes(url);
137
+ }).reduce((p, a) => {
138
+ p.push(a[1]);
139
+ return p;
140
+ }, [url]);
141
+ };
142
+ }
143
+ set(customRoutes = {}) {
144
+ for (let key in customRoutes) {
145
+ const path = customRoutes[key];
146
+ key = addLeadingSlash(key);
147
+ if (typeof path === 'string') {
148
+ this.conf.push([key, addLeadingSlash(path)]);
149
+ }
150
+ else if ((path === null || path === void 0 ? void 0 : path.length) > 0) {
151
+ this.conf.push(...path.map(p => [key, addLeadingSlash(p)]));
152
+ }
153
+ }
154
+ }
155
+ }
156
+ const routesAlias = new RoutesAlias();
116
157
 
117
158
  function processNavigateUrl(option) {
118
159
  var _a;
119
160
  const pathPieces = J(option.url);
120
161
  // 处理自定义路由
121
- Object.keys(routesAlias).forEach(key => {
122
- if (addLeadingSlash(key) === addLeadingSlash(pathPieces.pathname)) {
123
- pathPieces.pathname = routesAlias[key];
124
- }
125
- });
162
+ pathPieces.pathname = routesAlias.getAlias(addLeadingSlash(pathPieces.pathname));
126
163
  // 处理相对路径
127
164
  if ((_a = pathPieces === null || pathPieces === void 0 ? void 0 : pathPieces.pathname) === null || _a === void 0 ? void 0 : _a.includes('./')) {
128
165
  const parts = history.location.pathname.split('/');
@@ -146,9 +183,10 @@ async function navigate(option, method) {
146
183
  return new Promise((resolve, reject) => {
147
184
  const { success, complete, fail } = option;
148
185
  const unListen = history.listen(() => {
149
- success === null || success === void 0 ? void 0 : success();
150
- complete === null || complete === void 0 ? void 0 : complete();
151
- resolve();
186
+ const res = { errMsg: `${method}: ok` };
187
+ success === null || success === void 0 ? void 0 : success(res);
188
+ complete === null || complete === void 0 ? void 0 : complete(res);
189
+ resolve(res);
152
190
  unListen();
153
191
  });
154
192
  try {
@@ -158,7 +196,11 @@ async function navigate(option, method) {
158
196
  if (method === 'navigateTo') {
159
197
  history.push(pathPieces, state);
160
198
  }
161
- else if (method === 'redirectTo') {
199
+ else if (method === 'redirectTo' || method === 'switchTab') {
200
+ history.replace(pathPieces, state);
201
+ }
202
+ else if (method === 'reLaunch') {
203
+ stacks.delta = stacks.length;
162
204
  history.replace(pathPieces, state);
163
205
  }
164
206
  }
@@ -168,9 +210,10 @@ async function navigate(option, method) {
168
210
  }
169
211
  }
170
212
  catch (error) {
171
- fail === null || fail === void 0 ? void 0 : fail(error);
172
- complete === null || complete === void 0 ? void 0 : complete();
173
- reject(error);
213
+ const res = { errMsg: `${method}: fail ${error.message || error}` };
214
+ fail === null || fail === void 0 ? void 0 : fail(res);
215
+ complete === null || complete === void 0 ? void 0 : complete(res);
216
+ reject(res);
174
217
  }
175
218
  });
176
219
  }
@@ -187,15 +230,14 @@ function navigateBack(options = { delta: 1 }) {
187
230
  return navigate(options, 'navigateBack');
188
231
  }
189
232
  function switchTab(option) {
190
- // TODO: 清除掉所有的栈去目标页面
191
- return redirectTo(option);
233
+ return navigate(option, 'switchTab');
192
234
  }
193
235
  function reLaunch(option) {
194
- // TODO: 清除掉所有的栈去目标页面
195
- return redirectTo(option);
236
+ return navigate(option, 'reLaunch');
196
237
  }
197
238
  function getCurrentPages() {
198
- return stacks.get();
239
+ const pages = stacks.get();
240
+ return pages.map(e => (Object.assign(Object.assign({}, e), { route: e.path || '' })));
199
241
  }
200
242
 
201
243
  /**
@@ -841,108 +883,6 @@ var UniversalRouter = function () {
841
883
 
842
884
  UniversalRouter.pathToRegexp = pathToRegexp_1;
843
885
 
844
- const Taro = require('@tarojs/taro-h5');
845
- function initTabbar(config) {
846
- if (config.tabBar == null) {
847
- return;
848
- }
849
- // TODO: 找到 tabbar 的类型
850
- const tabbar = document.createElement('taro-tabbar');
851
- const homePage = config.pages ? config.pages[0] : '';
852
- tabbar.conf = config.tabBar;
853
- tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
854
- const routerConfig = config.router;
855
- tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
856
- if (routerConfig.customRoutes) {
857
- tabbar.conf.custom = true;
858
- tabbar.conf.customRoutes = routerConfig.customRoutes;
859
- }
860
- else {
861
- tabbar.conf.custom = false;
862
- tabbar.conf.customRoutes = {};
863
- }
864
- if (typeof routerConfig.basename !== 'undefined') {
865
- tabbar.conf.basename = routerConfig.basename;
866
- }
867
- const container = document.getElementById('container');
868
- // eslint-disable-next-line no-unused-expressions
869
- container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
870
- Taro.initTabBarApis(config);
871
- }
872
-
873
- const routerConfig = Object.create(null);
874
- function init(config) {
875
- var _a;
876
- config.router.mode = config.router.mode || 'hash';
877
- setHistoryMode(config.router.mode, config.router.basename);
878
- Object.assign(routerConfig, config);
879
- (_a = document.getElementById('app')) === null || _a === void 0 ? void 0 : _a.remove();
880
- const container = document.createElement('div');
881
- container.classList.add('taro-tabbar__container');
882
- container.id = 'container';
883
- const panel = document.createElement('div');
884
- panel.classList.add('taro-tabbar__panel');
885
- const app = document.createElement('div');
886
- app.id = 'app';
887
- app.classList.add('taro_router');
888
- panel.appendChild(app);
889
- container.appendChild(panel);
890
- document.body.appendChild(container);
891
- initTabbar(config);
892
- }
893
-
894
- let pageScrollFn;
895
- let pageDOM = window;
896
- function bindPageScroll(page, config) {
897
- pageDOM.removeEventListener('scroll', pageScrollFn);
898
- pageDOM = getScrollContainer();
899
- const distance = config.onReachBottomDistance || 50;
900
- let isReachBottom = false;
901
- pageScrollFn = function () {
902
- page.onPageScroll && page.onPageScroll({
903
- scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
904
- });
905
- if (isReachBottom && getOffset() > distance) {
906
- isReachBottom = false;
907
- }
908
- if (page.onReachBottom &&
909
- !isReachBottom &&
910
- getOffset() < distance) {
911
- isReachBottom = true;
912
- page.onReachBottom();
913
- }
914
- };
915
- pageDOM.addEventListener('scroll', pageScrollFn, false);
916
- }
917
- window.addEventListener('DOMSubtreeModified', (e) => {
918
- var _a;
919
- // @ts-ignore
920
- const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
921
- if (className && /taro-tabbar__/.test(className)) {
922
- pageDOM.removeEventListener('scroll', pageScrollFn);
923
- pageDOM = getScrollContainer();
924
- pageDOM.addEventListener('scroll', pageScrollFn, false);
925
- }
926
- }, false);
927
- function getScrollContainer() {
928
- if (document.querySelector('.taro-tabbar__tabbar') === null) {
929
- // 没设置tabbar
930
- return window;
931
- }
932
- else {
933
- // 有设置tabbar
934
- return document.querySelector('.taro-tabbar__panel') || window;
935
- }
936
- }
937
- function getOffset() {
938
- if (pageDOM instanceof Window) {
939
- return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
940
- }
941
- else {
942
- return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
943
- }
944
- }
945
-
946
886
  function createCommonjsModule(fn, module) {
947
887
  return module = { exports: {} }, fn(module, module.exports), module.exports;
948
888
  }
@@ -1494,125 +1434,369 @@ var queryString_5 = queryString.stringifyUrl;
1494
1434
  var queryString_6 = queryString.pick;
1495
1435
  var queryString_7 = queryString.exclude;
1496
1436
 
1497
- function getSearch() {
1498
- let search = '?';
1499
- if (routerConfig.router.mode === 'hash') {
1500
- const idx = location.hash.indexOf('?');
1501
- if (idx > -1) {
1502
- search = location.hash.slice(idx);
1437
+ let pageScrollFn;
1438
+ let pageDOM = window;
1439
+ function bindPageScroll(page, config) {
1440
+ pageDOM.removeEventListener('scroll', pageScrollFn);
1441
+ pageDOM = getScrollContainer();
1442
+ const distance = config.onReachBottomDistance || 50;
1443
+ let isReachBottom = false;
1444
+ pageScrollFn = function () {
1445
+ page.onPageScroll && page.onPageScroll({
1446
+ scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
1447
+ });
1448
+ if (isReachBottom && getOffset() > distance) {
1449
+ isReachBottom = false;
1503
1450
  }
1504
- }
1505
- else {
1506
- search = location.search;
1507
- }
1508
- return search.substr(1);
1451
+ if (page.onReachBottom &&
1452
+ !isReachBottom &&
1453
+ getOffset() < distance) {
1454
+ isReachBottom = true;
1455
+ page.onReachBottom();
1456
+ }
1457
+ };
1458
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
1509
1459
  }
1510
- const qs = function (stamp = 0) {
1511
- const search = getSearch();
1512
- const query = search
1513
- ? queryString.parse(search)
1514
- : {};
1515
- if (stamp) {
1516
- query.stamp = stamp.toString();
1460
+ window.addEventListener('DOMSubtreeModified', (e) => {
1461
+ const target = e.target;
1462
+ const className = target === null || target === void 0 ? void 0 : target.className;
1463
+ if (className && /taro_page/.test(className)) {
1464
+ pageDOM.removeEventListener('scroll', pageScrollFn);
1465
+ pageDOM = getScrollContainer();
1466
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
1517
1467
  }
1518
- return query;
1519
- };
1520
-
1521
- /* eslint-disable dot-notation */
1522
- function pageOnReady(page, onLoad = true) {
1468
+ }, false);
1469
+ function getScrollContainer() {
1523
1470
  var _a;
1524
- const pageEl = document.getElementById(page.path);
1525
- if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1526
- const el = pageEl.firstElementChild;
1527
- (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el).then(() => {
1528
- requestAnimationFrame(() => {
1529
- page.onReady();
1530
- pageEl['__isReady'] = true;
1531
- });
1532
- });
1533
- onLoad && (pageEl['__page'] = page);
1534
- }
1471
+ const id = (_a = Current.page) === null || _a === void 0 ? void 0 : _a.path;
1472
+ const el = (id
1473
+ ? document.getElementById(id)
1474
+ : document.querySelector('.taro_page') ||
1475
+ document.querySelector('.taro_router'));
1476
+ return el || window;
1535
1477
  }
1536
- function loadPage(page, pageConfig = {}, stacksIndex = 0) {
1537
- if (!page)
1538
- return;
1539
- const pageEl = document.getElementById(page.path);
1540
- if (pageEl) {
1541
- pageEl.style.display = 'block';
1478
+ function getOffset() {
1479
+ if (pageDOM instanceof Window) {
1480
+ return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
1542
1481
  }
1543
1482
  else {
1544
- page.onLoad(qs(stacksIndex), () => pageOnReady(page, true));
1483
+ return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
1545
1484
  }
1546
- stacks.push(page);
1547
- page.onShow();
1548
- bindPageScroll(page, pageConfig);
1549
- }
1550
- function unloadPage(page, delta = 1) {
1551
- if (!page)
1552
- return;
1553
- stacks.delta = --delta;
1554
- stacks.pop();
1555
- page.onUnload();
1556
- if (delta >= 1)
1557
- unloadPage(stacks.last, delta);
1558
- }
1559
- function showPage(page, pageConfig = {}, stacksIndex = 0) {
1560
- if (!page)
1485
+ }
1486
+
1487
+ /**
1488
+ * 插入页面动画需要的样式
1489
+ */
1490
+ function loadAnimateStyle(ms = 300) {
1491
+ const css = `
1492
+ .taro_router .taro_page {
1493
+ position: absolute;
1494
+ left: 0;
1495
+ top: 0;
1496
+ width: 100%;
1497
+ height: 100%;
1498
+ transform: translate3d(100%, 0, 0);
1499
+ transition: transform ${ms}ms;
1500
+ }
1501
+
1502
+ .taro_router .taro_page.taro_tabbar_page {
1503
+ transform: none;
1504
+ }
1505
+
1506
+ .taro_router .taro_page.taro_page_show {
1507
+ transform: translate3d(0, 0, 0);
1508
+ }`;
1509
+ const style = document.createElement('style');
1510
+ style.innerHTML = css;
1511
+ document.getElementsByTagName('head')[0].appendChild(style);
1512
+ }
1513
+
1514
+ // @ts-nocheck
1515
+ function initTabbar(config) {
1516
+ if (config.tabBar == null) {
1561
1517
  return;
1562
- page.onShow();
1563
- const pageEl = document.getElementById(page.path);
1564
- if (pageEl) {
1565
- pageEl.style.display = 'block';
1518
+ }
1519
+ // TODO: custom-tab-bar
1520
+ const tabbar = document.createElement('taro-tabbar');
1521
+ const homePage = config.entryPagePath || (config.pages ? config.pages[0] : '');
1522
+ tabbar.conf = config.tabBar;
1523
+ tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
1524
+ const routerConfig = config.router;
1525
+ tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
1526
+ if (routerConfig.customRoutes) {
1527
+ tabbar.conf.custom = true;
1528
+ tabbar.conf.customRoutes = routerConfig.customRoutes;
1566
1529
  }
1567
1530
  else {
1568
- page.onLoad(qs(stacksIndex), () => pageOnReady(page, false));
1531
+ tabbar.conf.custom = false;
1532
+ tabbar.conf.customRoutes = {};
1533
+ }
1534
+ if (typeof routerConfig.basename !== 'undefined') {
1535
+ tabbar.conf.basename = routerConfig.basename;
1536
+ }
1537
+ const container = document.getElementById('container');
1538
+ container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
1539
+ initTabBarApis(config);
1540
+ }
1541
+
1542
+ function setDisplay(el, type = '') {
1543
+ if (el) {
1544
+ el.style.display = type;
1569
1545
  }
1570
- bindPageScroll(page, pageConfig);
1571
1546
  }
1572
- function hidePage(page) {
1573
- if (!page)
1574
- return;
1575
- // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
1576
- const pageEl = document.getElementById(page.path);
1577
- if (pageEl) {
1578
- pageEl.style.display = 'none';
1579
- page.onHide();
1547
+ class PageHandler {
1548
+ constructor(config) {
1549
+ this.defaultAnimation = { duration: 300, delay: 50 };
1550
+ this.config = config;
1551
+ this.mount();
1580
1552
  }
1581
- else {
1582
- setTimeout(() => hidePage(page), 0);
1553
+ get appId() { return 'app'; }
1554
+ get router() { return this.config.router; }
1555
+ get routerMode() { return this.router.mode || 'hash'; }
1556
+ get customRoutes() { return this.router.customRoutes || {}; }
1557
+ get routes() { return this.config.routes; }
1558
+ get tabBarList() { var _a; return ((_a = this.config.tabBar) === null || _a === void 0 ? void 0 : _a.list) || []; }
1559
+ get PullDownRefresh() { return this.config.PullDownRefresh; }
1560
+ get animation() { var _a, _b; return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.animation) !== null && _b !== void 0 ? _b : this.defaultAnimation; }
1561
+ get animationDelay() {
1562
+ var _a;
1563
+ return typeof this.animation === 'object'
1564
+ ? this.animation.delay
1565
+ : this.animation
1566
+ ? (_a = this.defaultAnimation) === null || _a === void 0 ? void 0 : _a.delay
1567
+ : 0;
1568
+ }
1569
+ get animationDuration() {
1570
+ var _a;
1571
+ return typeof this.animation === 'object'
1572
+ ? this.animation.duration
1573
+ : this.animation
1574
+ ? (_a = this.defaultAnimation) === null || _a === void 0 ? void 0 : _a.duration
1575
+ : 0;
1576
+ }
1577
+ set pathname(p) { this.router.pathname = p; }
1578
+ get pathname() { return this.router.pathname; }
1579
+ get basename() { return this.router.basename || ''; }
1580
+ get pageConfig() {
1581
+ return this.routes.find(r => {
1582
+ var _a;
1583
+ const routePath = stripBasename(this.pathname, this.basename);
1584
+ const pagePath = addLeadingSlash(r.path);
1585
+ return pagePath === routePath || ((_a = routesAlias.getConfig(pagePath)) === null || _a === void 0 ? void 0 : _a.includes(routePath));
1586
+ });
1587
+ }
1588
+ get isTabBar() {
1589
+ var _a;
1590
+ const routePath = stripBasename(this.pathname, this.basename);
1591
+ const pagePath = ((_a = Object.entries(this.customRoutes).find(([, target]) => {
1592
+ if (typeof target === 'string') {
1593
+ return target === routePath;
1594
+ }
1595
+ else if ((target === null || target === void 0 ? void 0 : target.length) > 0) {
1596
+ return target.includes(routePath);
1597
+ }
1598
+ return false;
1599
+ })) === null || _a === void 0 ? void 0 : _a[0]) || routePath;
1600
+ return !!pagePath && this.tabBarList.some(t => t.pagePath === pagePath);
1601
+ }
1602
+ isSamePage(page) {
1603
+ const routePath = stripBasename(this.pathname, this.basename);
1604
+ const pagePath = stripBasename(page === null || page === void 0 ? void 0 : page.path, this.basename);
1605
+ return pagePath.startsWith(routePath + '?');
1606
+ }
1607
+ get search() {
1608
+ let search = '?';
1609
+ if (this.routerMode) {
1610
+ const idx = location.hash.indexOf('?');
1611
+ if (idx > -1) {
1612
+ search = location.hash.slice(idx);
1613
+ }
1614
+ }
1615
+ else {
1616
+ search = location.search;
1617
+ }
1618
+ return search.substr(1);
1619
+ }
1620
+ getQuery(stamp = 0) {
1621
+ const search = this.search;
1622
+ const query = search
1623
+ ? queryString.parse(search)
1624
+ : {};
1625
+ if (stamp) {
1626
+ query.stamp = stamp.toString();
1627
+ }
1628
+ return query;
1629
+ }
1630
+ mount() {
1631
+ var _a;
1632
+ setHistoryMode(this.routerMode, this.router.basename);
1633
+ (_a = document.getElementById('app')) === null || _a === void 0 ? void 0 : _a.remove();
1634
+ this.animation && loadAnimateStyle(this.animationDuration);
1635
+ const app = document.createElement('div');
1636
+ app.id = this.appId;
1637
+ app.classList.add('taro_router');
1638
+ if (this.tabBarList.length > 1) {
1639
+ const container = document.createElement('div');
1640
+ container.classList.add('taro-tabbar__container');
1641
+ container.id = 'container';
1642
+ const panel = document.createElement('div');
1643
+ panel.classList.add('taro-tabbar__panel');
1644
+ panel.appendChild(app);
1645
+ container.appendChild(panel);
1646
+ document.body.appendChild(container);
1647
+ initTabbar(this.config);
1648
+ }
1649
+ else {
1650
+ document.body.appendChild(app);
1651
+ }
1652
+ }
1653
+ onReady(page, onLoad = true) {
1654
+ var _a, _b;
1655
+ const pageEl = document.getElementById(page.path);
1656
+ if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1657
+ const el = pageEl.firstElementChild;
1658
+ (_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(() => {
1659
+ requestAnimationFrame(() => {
1660
+ var _a;
1661
+ (_a = page.onReady) === null || _a === void 0 ? void 0 : _a.call(page);
1662
+ pageEl['__isReady'] = true;
1663
+ });
1664
+ });
1665
+ onLoad && (pageEl['__page'] = page);
1666
+ }
1667
+ }
1668
+ load(page, pageConfig = {}, stacksIndex = 0) {
1669
+ var _a;
1670
+ if (!page)
1671
+ return;
1672
+ let pageEl = document.getElementById(page.path);
1673
+ if (pageEl) {
1674
+ setDisplay(pageEl);
1675
+ this.isTabBar && pageEl.classList.add('taro_tabbar_page');
1676
+ this.addAnimation(pageEl, stacksIndex === 0);
1677
+ }
1678
+ else {
1679
+ page.onLoad(this.getQuery(stacksIndex), () => {
1680
+ pageEl = document.getElementById(page.path);
1681
+ this.isTabBar && (pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.add('taro_tabbar_page'));
1682
+ this.addAnimation(pageEl, stacksIndex === 0);
1683
+ this.onReady(page, true);
1684
+ });
1685
+ }
1686
+ stacks.push(page);
1687
+ (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
1688
+ bindPageScroll(page, pageConfig);
1689
+ }
1690
+ unload(page, delta = 1, top = false) {
1691
+ var _a;
1692
+ if (!page)
1693
+ return;
1694
+ stacks.delta = --delta;
1695
+ stacks.pop();
1696
+ if (this.animation && top) {
1697
+ if (this.unloadTimer) {
1698
+ clearTimeout(this.unloadTimer);
1699
+ (_a = this.lastUnloadPage) === null || _a === void 0 ? void 0 : _a.onUnload();
1700
+ this.unloadTimer = null;
1701
+ }
1702
+ this.lastUnloadPage = page;
1703
+ const pageEl = document.getElementById(page.path);
1704
+ pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_show');
1705
+ this.unloadTimer = setTimeout(() => {
1706
+ var _a;
1707
+ this.unloadTimer = null;
1708
+ (_a = this.lastUnloadPage) === null || _a === void 0 ? void 0 : _a.onUnload();
1709
+ }, this.animationDuration);
1710
+ }
1711
+ else {
1712
+ const pageEl = document.getElementById(page.path);
1713
+ pageEl === null || pageEl === void 0 ? void 0 : pageEl.classList.remove('taro_page_show');
1714
+ page === null || page === void 0 ? void 0 : page.onUnload();
1715
+ }
1716
+ if (delta >= 1)
1717
+ this.unload(stacks.last, delta);
1718
+ }
1719
+ show(page, pageConfig = {}, stacksIndex = 0) {
1720
+ var _a;
1721
+ if (!page)
1722
+ return;
1723
+ (_a = page.onShow) === null || _a === void 0 ? void 0 : _a.call(page);
1724
+ let pageEl = document.getElementById(page.path);
1725
+ if (pageEl) {
1726
+ setDisplay(pageEl);
1727
+ this.addAnimation(pageEl, stacksIndex === 0);
1728
+ }
1729
+ else {
1730
+ page.onLoad(this.getQuery(stacksIndex), () => {
1731
+ pageEl = document.getElementById(page.path);
1732
+ this.addAnimation(pageEl, stacksIndex === 0);
1733
+ this.onReady(page, false);
1734
+ });
1735
+ }
1736
+ bindPageScroll(page, pageConfig);
1737
+ }
1738
+ hide(page) {
1739
+ var _a;
1740
+ if (!page)
1741
+ return;
1742
+ // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
1743
+ const pageEl = document.getElementById(page.path);
1744
+ if (pageEl) {
1745
+ if (this.hideTimer) {
1746
+ clearTimeout(this.hideTimer);
1747
+ this.hideTimer = null;
1748
+ setDisplay(this.lastHidePage, 'none');
1749
+ }
1750
+ this.lastHidePage = pageEl;
1751
+ this.hideTimer = setTimeout(() => {
1752
+ this.hideTimer = null;
1753
+ setDisplay(this.lastHidePage, 'none');
1754
+ }, this.animationDelay);
1755
+ (_a = page.onHide) === null || _a === void 0 ? void 0 : _a.call(page);
1756
+ }
1757
+ else {
1758
+ setTimeout(() => this.hide(page), 0);
1759
+ }
1760
+ }
1761
+ addAnimation(pageEl, first = false) {
1762
+ if (!pageEl)
1763
+ return;
1764
+ if (this.animation && !first) {
1765
+ setTimeout(() => {
1766
+ pageEl.classList.add('taro_page_show');
1767
+ }, this.animationDelay);
1768
+ }
1769
+ else {
1770
+ pageEl.classList.add('taro_page_show');
1771
+ }
1583
1772
  }
1584
1773
  }
1585
1774
 
1586
1775
  /* eslint-disable dot-notation */
1587
1776
  function createRouter(app, config, framework) {
1588
- var _a;
1589
- init(config);
1590
- const routes = [];
1591
- const alias = (_a = config.router.customRoutes) !== null && _a !== void 0 ? _a : {};
1777
+ var _a, _b, _c;
1778
+ const handler = new PageHandler(config);
1592
1779
  const runtimeHooks = container.get(SERVICE_IDENTIFIER.Hooks);
1593
- setRoutesAlias(alias);
1594
- for (let i = 0; i < config.routes.length; i++) {
1595
- const route = config.routes[i];
1596
- const path = addLeadingSlash(route.path);
1597
- routes.push({
1598
- path: alias[path] || path,
1599
- action: route.load
1600
- });
1601
- }
1602
- const basename = config.router.basename;
1780
+ routesAlias.set(handler.router.customRoutes);
1781
+ const basename = handler.router.basename;
1782
+ const routes = handler.routes.map(route => ({
1783
+ path: routesAlias.getAll(addLeadingSlash(route.path)),
1784
+ action: route.load
1785
+ }));
1786
+ const entryPagePath = config.entryPagePath || ((_a = routes[0].path) === null || _a === void 0 ? void 0 : _a[0]);
1603
1787
  const router = new UniversalRouter(routes, { baseUrl: basename || '' });
1604
- app.onLaunch();
1788
+ (_b = app.onLaunch) === null || _b === void 0 ? void 0 : _b.call(app);
1605
1789
  const render = async ({ location, action }) => {
1606
1790
  var _a, _b, _c, _d;
1607
- routerConfig.router.pathname = location.pathname;
1791
+ handler.pathname = location.pathname;
1608
1792
  let element;
1609
1793
  try {
1610
- element = await router.resolve(config.router.forcePath || location.pathname);
1794
+ element = await router.resolve(handler.router.forcePath || handler.pathname);
1611
1795
  }
1612
1796
  catch (error) {
1613
1797
  if (error.status === 404) {
1614
1798
  (_a = app.onPageNotFound) === null || _a === void 0 ? void 0 : _a.call(app, {
1615
- path: location.pathname
1799
+ path: handler.pathname
1616
1800
  });
1617
1801
  }
1618
1802
  else {
@@ -1621,14 +1805,11 @@ function createRouter(app, config, framework) {
1621
1805
  }
1622
1806
  if (!element)
1623
1807
  return;
1624
- const pageConfig = config.routes.find(r => {
1625
- const path = addLeadingSlash(r.path);
1626
- return path === location.pathname || alias[path] === location.pathname;
1627
- });
1808
+ const pageConfig = handler.pageConfig;
1628
1809
  let enablePullDownRefresh = false;
1629
1810
  eventCenter.trigger('__taroRouterChange', {
1630
1811
  toLocation: {
1631
- path: location.pathname
1812
+ path: handler.pathname
1632
1813
  }
1633
1814
  });
1634
1815
  if (pageConfig) {
@@ -1636,53 +1817,56 @@ function createRouter(app, config, framework) {
1636
1817
  enablePullDownRefresh = pageConfig.enablePullDownRefresh;
1637
1818
  }
1638
1819
  const currentPage = Current.page;
1639
- const pathname = location.pathname;
1820
+ const pathname = handler.pathname;
1640
1821
  let shouldLoad = false;
1641
1822
  if (action === 'POP') {
1642
1823
  // NOTE: 浏览器事件退后多次时,该事件只会被触发一次
1643
1824
  const prevIndex = stacks.getPrevIndex(pathname);
1644
1825
  const delta = stacks.getDelta(pathname);
1645
- unloadPage(currentPage, delta);
1826
+ handler.unload(currentPage, delta, prevIndex > -1);
1646
1827
  if (prevIndex > -1) {
1647
- showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1828
+ handler.show(stacks.getItem(prevIndex), pageConfig, prevIndex);
1648
1829
  }
1649
1830
  else {
1650
1831
  shouldLoad = true;
1651
1832
  }
1652
1833
  }
1653
- else if (action === 'PUSH') {
1654
- hidePage(currentPage);
1655
- shouldLoad = true;
1656
- }
1657
- else if (action === 'REPLACE') {
1658
- if (isTabBar(config)) {
1659
- hidePage(currentPage);
1660
- const prevIndex = stacks.getPrevIndex(pathname);
1834
+ else {
1835
+ if (handler.isTabBar) {
1836
+ if (handler.isSamePage(currentPage))
1837
+ return;
1838
+ const prevIndex = stacks.getPrevIndex(pathname, 0);
1839
+ handler.hide(currentPage);
1661
1840
  if (prevIndex > -1) {
1662
1841
  // NOTE: tabbar 页且之前出现过,直接复用
1663
- return showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1842
+ return handler.show(stacks.getItem(prevIndex), pageConfig, prevIndex);
1664
1843
  }
1665
1844
  }
1666
- else {
1667
- unloadPage(currentPage);
1845
+ else if (action === 'REPLACE') {
1846
+ const delta = stacks.getDelta(pathname);
1847
+ // NOTE: 页面路由记录并不会清空,只是移除掉缓存的 stack 以及页面
1848
+ handler.unload(currentPage, delta);
1849
+ }
1850
+ else if (action === 'PUSH') {
1851
+ handler.hide(currentPage);
1668
1852
  }
1669
1853
  shouldLoad = true;
1670
1854
  }
1671
- if (shouldLoad) {
1855
+ if (shouldLoad || stacks.length < 1) {
1672
1856
  const el = (_c = element.default) !== null && _c !== void 0 ? _c : element;
1673
1857
  const loadConfig = Object.assign({}, pageConfig);
1674
1858
  const stacksIndex = stacks.length;
1675
1859
  delete loadConfig['path'];
1676
1860
  delete loadConfig['load'];
1677
- 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);
1678
- return loadPage(page, pageConfig, stacksIndex);
1861
+ const page = createPageConfig(enablePullDownRefresh ? (_d = runtimeHooks.createPullDownComponent) === null || _d === void 0 ? void 0 : _d.call(runtimeHooks, el, location.pathname, framework, handler.PullDownRefresh) : el, pathname + stringify(handler.getQuery(stacksIndex)), {}, loadConfig);
1862
+ return handler.load(page, pageConfig, stacksIndex);
1679
1863
  }
1680
1864
  };
1681
1865
  if (history.location.pathname === '/') {
1682
- history.replace(prependBasename(routes[0].path + history.location.search));
1866
+ history.replace(prependBasename(entryPagePath + history.location.search));
1683
1867
  }
1684
1868
  render({ location: history.location, action: r.Push });
1685
- app.onShow(qs(stacks.length));
1869
+ (_c = app.onShow) === null || _c === void 0 ? void 0 : _c.call(app, handler.getQuery(stacks.length));
1686
1870
  return history.listen(render);
1687
1871
  }
1688
1872