@tarojs/router 3.3.14 → 3.3.15

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,4 @@
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
2
 
3
3
  function _extends() {
4
4
  _extends = Object.assign || function (target) {
@@ -47,9 +47,54 @@ function setHistoryMode(mode, base = '/') {
47
47
  }
48
48
  function prependBasename(url = '') {
49
49
  return basename.replace(/\/$/, '') + '/' + url.replace(/^\//, '');
50
- }
50
+ }
51
+ const hasBasename = (path, prefix) => new RegExp('^' + prefix + '(\\/|\\?|#|$)', 'i').test(path);
52
+ const stripBasename = (path, prefix) => hasBasename(path, prefix) ? path.substr(prefix.length) : path;
51
53
 
52
- const stacks = [];
54
+ class Stacks {
55
+ constructor() {
56
+ this.stacks = [];
57
+ this.backDelta = 0;
58
+ }
59
+ set delta(delta) {
60
+ if (delta > 0) {
61
+ this.backDelta = delta;
62
+ }
63
+ else {
64
+ --this.backDelta;
65
+ }
66
+ }
67
+ get length() {
68
+ return this.stacks.length;
69
+ }
70
+ get last() {
71
+ return this.stacks[this.length - 1];
72
+ }
73
+ get() {
74
+ return this.stacks;
75
+ }
76
+ getItem(index) {
77
+ return this.stacks[index];
78
+ }
79
+ getDelta(pathname) {
80
+ if (this.backDelta >= 1) {
81
+ return this.backDelta;
82
+ }
83
+ // 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;
86
+ }
87
+ getPrevIndex(pathname) {
88
+ return this.length - 1 - this.getDelta(pathname);
89
+ }
90
+ pop() {
91
+ return this.stacks.pop();
92
+ }
93
+ push(page) {
94
+ return this.stacks.push(page);
95
+ }
96
+ }
97
+ const stacks = new Stacks();
53
98
 
54
99
  let routesAlias = {};
55
100
  function setRoutesAlias(alias) {
@@ -61,25 +106,6 @@ function addLeadingSlash(path) {
61
106
  }
62
107
  return path.charAt(0) === '/' ? path : '/' + path;
63
108
  }
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;
79
- }
80
- };
81
- };
82
- const stripBasename = (path, basename) => path.startsWith(basename) ? path.replace(basename, '') : path;
83
109
  const isTabBar = (config) => {
84
110
  var _a, _b;
85
111
  const { customRoutes = {}, basename = '', pathname } = config.router;
@@ -89,6 +115,7 @@ const isTabBar = (config) => {
89
115
  };
90
116
 
91
117
  function processNavigateUrl(option) {
118
+ var _a;
92
119
  const pathPieces = J(option.url);
93
120
  // 处理自定义路由
94
121
  Object.keys(routesAlias).forEach(key => {
@@ -96,6 +123,18 @@ function processNavigateUrl(option) {
96
123
  pathPieces.pathname = routesAlias[key];
97
124
  }
98
125
  });
126
+ // 处理相对路径
127
+ if ((_a = pathPieces === null || pathPieces === void 0 ? void 0 : pathPieces.pathname) === null || _a === void 0 ? void 0 : _a.includes('./')) {
128
+ const parts = history.location.pathname.split('/');
129
+ parts.pop();
130
+ pathPieces.pathname.split('/').forEach((item) => {
131
+ if (item === '.') {
132
+ return;
133
+ }
134
+ item === '..' ? parts.pop() : parts.push(item);
135
+ });
136
+ pathPieces.pathname = parts.join('/');
137
+ }
99
138
  // 处理 basename
100
139
  pathPieces.pathname = prependBasename(pathPieces.pathname);
101
140
  // hack fix history v5 bug: https://github.com/remix-run/history/issues/814
@@ -124,7 +163,7 @@ async function navigate(option, method) {
124
163
  }
125
164
  }
126
165
  else if (method === 'navigateBack') {
127
- setHistoryBackDelta(option.delta);
166
+ stacks.delta = option.delta;
128
167
  history.go(-option.delta);
129
168
  }
130
169
  }
@@ -156,7 +195,7 @@ function reLaunch(option) {
156
195
  return redirectTo(option);
157
196
  }
158
197
  function getCurrentPages() {
159
- return stacks;
198
+ return stacks.get();
160
199
  }
161
200
 
162
201
  /**
@@ -802,6 +841,7 @@ var UniversalRouter = function () {
802
841
 
803
842
  UniversalRouter.pathToRegexp = pathToRegexp_1;
804
843
 
844
+ const Taro = require('@tarojs/taro-h5');
805
845
  function initTabbar(config) {
806
846
  if (config.tabBar == null) {
807
847
  return;
@@ -813,7 +853,6 @@ function initTabbar(config) {
813
853
  tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
814
854
  const routerConfig = config.router;
815
855
  tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
816
- tabbar.conf.custom = !!routerConfig.customRoutes;
817
856
  if (routerConfig.customRoutes) {
818
857
  tabbar.conf.custom = true;
819
858
  tabbar.conf.customRoutes = routerConfig.customRoutes;
@@ -828,6 +867,7 @@ function initTabbar(config) {
828
867
  const container = document.getElementById('container');
829
868
  // eslint-disable-next-line no-unused-expressions
830
869
  container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
870
+ Taro.initTabBarApis(config);
831
871
  }
832
872
 
833
873
  const routerConfig = Object.create(null);
@@ -851,6 +891,58 @@ function init(config) {
851
891
  initTabbar(config);
852
892
  }
853
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
+
854
946
  function createCommonjsModule(fn, module) {
855
947
  return module = { exports: {} }, fn(module, module.exports), module.exports;
856
948
  }
@@ -1402,12 +1494,23 @@ var queryString_5 = queryString.stringifyUrl;
1402
1494
  var queryString_6 = queryString.pick;
1403
1495
  var queryString_7 = queryString.exclude;
1404
1496
 
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);
1503
+ }
1504
+ }
1505
+ else {
1506
+ search = location.search;
1507
+ }
1508
+ return search.substr(1);
1509
+ }
1405
1510
  const qs = function (stamp = 0) {
1406
- const search = routerConfig.router.mode === 'hash'
1407
- ? location.hash.slice(routerConfig.router.pathname.length + 1)
1408
- : location.search;
1511
+ const search = getSearch();
1409
1512
  const query = search
1410
- ? queryString.parse(search.substr(1))
1513
+ ? queryString.parse(search)
1411
1514
  : {};
1412
1515
  if (stamp) {
1413
1516
  query.stamp = stamp.toString();
@@ -1415,94 +1518,12 @@ const qs = function (stamp = 0) {
1415
1518
  return query;
1416
1519
  };
1417
1520
 
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
1521
  /* 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) {
1522
+ function pageOnReady(page, onLoad = true) {
1502
1523
  var _a;
1524
+ const pageEl = document.getElementById(page.path);
1503
1525
  if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1504
1526
  const el = pageEl.firstElementChild;
1505
- // eslint-disable-next-line no-unused-expressions
1506
1527
  (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el).then(() => {
1507
1528
  requestAnimationFrame(() => {
1508
1529
  page.onReady();
@@ -1512,23 +1533,57 @@ function pageOnReady(pageEl, page, onLoad = true) {
1512
1533
  onLoad && (pageEl['__page'] = page);
1513
1534
  }
1514
1535
  }
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 || {});
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';
1530
1542
  }
1543
+ else {
1544
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, true));
1545
+ }
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);
1531
1558
  }
1559
+ function showPage(page, pageConfig = {}, stacksIndex = 0) {
1560
+ if (!page)
1561
+ return;
1562
+ page.onShow();
1563
+ const pageEl = document.getElementById(page.path);
1564
+ if (pageEl) {
1565
+ pageEl.style.display = 'block';
1566
+ }
1567
+ else {
1568
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, false));
1569
+ }
1570
+ bindPageScroll(page, pageConfig);
1571
+ }
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();
1580
+ }
1581
+ else {
1582
+ setTimeout(() => hidePage(page), 0);
1583
+ }
1584
+ }
1585
+
1586
+ /* eslint-disable dot-notation */
1532
1587
  function createRouter(app, config, framework) {
1533
1588
  var _a;
1534
1589
  init(config);
@@ -1547,7 +1602,7 @@ function createRouter(app, config, framework) {
1547
1602
  const basename = config.router.basename;
1548
1603
  const router = new UniversalRouter(routes, { baseUrl: basename || '' });
1549
1604
  app.onLaunch();
1550
- const render = throttle(async ({ location, action }) => {
1605
+ const render = async ({ location, action }) => {
1551
1606
  var _a, _b, _c, _d;
1552
1607
  routerConfig.router.pathname = location.pathname;
1553
1608
  let element;
@@ -1580,65 +1635,49 @@ function createRouter(app, config, framework) {
1580
1635
  document.title = (_b = pageConfig.navigationBarTitleText) !== null && _b !== void 0 ? _b : document.title;
1581
1636
  enablePullDownRefresh = pageConfig.enablePullDownRefresh;
1582
1637
  }
1638
+ const currentPage = Current.page;
1639
+ const pathname = location.pathname;
1583
1640
  let shouldLoad = false;
1584
1641
  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);
1642
+ // NOTE: 浏览器事件退后多次时,该事件只会被触发一次
1643
+ const prevIndex = stacks.getPrevIndex(pathname);
1644
+ const delta = stacks.getDelta(pathname);
1645
+ unloadPage(currentPage, delta);
1646
+ if (prevIndex > -1) {
1647
+ showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1603
1648
  }
1604
1649
  else {
1605
1650
  shouldLoad = true;
1606
1651
  }
1607
1652
  }
1608
1653
  else if (action === 'PUSH') {
1609
- hidePage(Current.page);
1654
+ hidePage(currentPage);
1610
1655
  shouldLoad = true;
1611
1656
  }
1612
1657
  else if (action === 'REPLACE') {
1613
1658
  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
- });
1659
+ hidePage(currentPage);
1660
+ const prevIndex = stacks.getPrevIndex(pathname);
1620
1661
  if (prevIndex > -1) {
1621
- // tabbar 页且之前出现过,直接复用
1622
- const prev = stacks[prevIndex];
1623
- return showPage(prev, pageConfig, prevIndex);
1662
+ // NOTE: tabbar 页且之前出现过,直接复用
1663
+ return showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1624
1664
  }
1625
1665
  }
1626
1666
  else {
1627
- unloadPage(Current.page);
1667
+ unloadPage(currentPage);
1628
1668
  }
1629
1669
  shouldLoad = true;
1630
1670
  }
1631
1671
  if (shouldLoad) {
1632
1672
  const el = (_c = element.default) !== null && _c !== void 0 ? _c : element;
1633
1673
  const loadConfig = Object.assign({}, pageConfig);
1674
+ const stacksIndex = stacks.length;
1634
1675
  delete loadConfig['path'];
1635
1676
  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);
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);
1640
1679
  }
1641
- }, 500);
1680
+ };
1642
1681
  if (history.location.pathname === '/') {
1643
1682
  history.replace(prependBasename(routes[0].path + history.location.search));
1644
1683
  }