@tarojs/router 3.3.12 → 3.3.16

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) {
@@ -21,14 +21,14 @@ function _extends() {
21
21
  var r,B=r||(r={});B.Pop="POP";B.Push="PUSH";B.Replace="REPLACE";var C="production"!==process.env.NODE_ENV?function(b){return Object.freeze(b)}:function(b){return b};function D(b,h){if(!b){"undefined"!==typeof console&&console.warn(h);try{throw Error(h);}catch(k){}}}function E(b){b.preventDefault();b.returnValue="";}
22
22
  function F(){var b=[];return {get length(){return b.length},push:function(h){b.push(h);return function(){b=b.filter(function(k){return k!==h});}},call:function(h){b.forEach(function(k){return k&&k(h)});}}}function H(){return Math.random().toString(36).substr(2,8)}function I(b){var h=b.pathname,k=b.search;b=b.hash;return (void 0===h?"/":h)+(void 0===k?"":k)+(void 0===b?"":b)}
23
23
  function J(b){var h={};if(b){var k=b.indexOf("#");0<=k&&(h.hash=b.substr(k),b=b.substr(0,k));k=b.indexOf("?");0<=k&&(h.search=b.substr(k),b=b.substr(0,k));b&&(h.pathname=b);}return h}
24
- function createBrowserHistory(b){function h(){var c=p.location,a=m.state||{};return [a.idx,C({pathname:c.pathname,search:c.search,hash:c.hash,state:a.usr||null,key:a.key||"default"})]}function k(c){return "string"===typeof c?c:I(c)}function x(c,a){void 0===a&&(a=null);return C(_extends({},q,"string"===typeof c?J(c):c,{state:a,key:H()}))}function z(c){t=c;c=h();v=c[0];q=c[1];d.call({action:t,location:q});}function A(c,a){function e(){A(c,a);}var l=r.Push,g=x(c,a);if(!f.length||(f.call({action:l,
25
- location:g,retry:e}),!1)){var n=[{usr:g.state,key:g.key,idx:v+1},k(g)];g=n[0];n=n[1];try{m.pushState(g,"",n);}catch(G){p.location.assign(n);}z(l);}}function y(c,a){function e(){y(c,a);}var l=r.Replace,g=x(c,a);f.length&&(f.call({action:l,location:g,retry:e}),1)||(g=[{usr:g.state,key:g.key,idx:v},k(g)],m.replaceState(g[0],"",g[1]),z(l));}function w(c){m.go(c);}void 0===b&&(b={});b=b.window;var p=void 0===b?document.defaultView:b,m=p.history,u=null;p.addEventListener("popstate",function(){if(u)f.call(u),
26
- u=null;else {var c=r.Pop,a=h(),e=a[0];a=a[1];if(f.length)if(null!=e){var l=v-e;l&&(u={action:c,location:a,retry:function(){w(-1*l);}},w(l));}else "production"!==process.env.NODE_ENV?D(!1,"You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."):void 0;else z(c);}});var t=
27
- r.Pop;b=h();var v=b[0],q=b[1],d=F(),f=F();null==v&&(v=0,m.replaceState(_extends({},m.state,{idx:v}),""));return {get action(){return t},get location(){return q},createHref:k,push:A,replace:y,go:w,back:function(){w(-1);},forward:function(){w(1);},listen:function(c){return d.push(c)},block:function(c){var a=f.push(c);1===f.length&&p.addEventListener("beforeunload",E);return function(){a();f.length||p.removeEventListener("beforeunload",E);}}}}function createHashHistory(b){function h(){var a=J(m.location.hash.substr(1)),e=a.pathname,l=a.search;a=a.hash;var g=u.state||{};return [g.idx,C({pathname:void 0===e?"/":e,search:void 0===l?"":l,hash:void 0===a?"":a,state:g.usr||null,key:g.key||"default"})]}function k(){if(t)c.call(t),t=null;else {var a=r.Pop,e=h(),l=e[0];e=e[1];if(c.length)if(null!=l){var g=q-l;g&&(t={action:a,location:e,retry:function(){p(-1*g);}},p(g));}else "production"!==process.env.NODE_ENV?D(!1,"You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."):
28
- void 0;else A(a);}}function x(a){var e=document.querySelector("base"),l="";e&&e.getAttribute("href")&&(e=m.location.href,l=e.indexOf("#"),l=-1===l?e:e.slice(0,l));return l+"#"+("string"===typeof a?a:I(a))}function z(a,e){void 0===e&&(e=null);return C(_extends({},d,"string"===typeof a?J(a):a,{state:e,key:H()}))}function A(a){v=a;a=h();q=a[0];d=a[1];f.call({action:v,location:d});}function y(a,e){function l(){y(a,e);}var g=r.Push,n=z(a,e);"production"!==process.env.NODE_ENV?D("/"===n.pathname.charAt(0),
29
- "Relative pathnames are not supported in hash history.push("+JSON.stringify(a)+")"):void 0;if(!c.length||(c.call({action:g,location:n,retry:l}),!1)){var G=[{usr:n.state,key:n.key,idx:q+1},x(n)];n=G[0];G=G[1];try{u.pushState(n,"",G);}catch(K){m.location.assign(G);}A(g);}}function w(a,e){function l(){w(a,e);}var g=r.Replace,n=z(a,e);"production"!==process.env.NODE_ENV?D("/"===n.pathname.charAt(0),"Relative pathnames are not supported in hash history.replace("+JSON.stringify(a)+")"):void 0;c.length&&(c.call({action:g,
30
- location:n,retry:l}),1)||(n=[{usr:n.state,key:n.key,idx:q},x(n)],u.replaceState(n[0],"",n[1]),A(g));}function p(a){u.go(a);}void 0===b&&(b={});b=b.window;var m=void 0===b?document.defaultView:b,u=m.history,t=null;m.addEventListener("popstate",k);m.addEventListener("hashchange",function(){var a=h()[1];I(a)!==I(d)&&k();});var v=r.Pop;b=h();var q=b[0],d=b[1],f=F(),c=F();null==q&&(q=0,u.replaceState(_extends({},u.state,{idx:q}),""));return {get action(){return v},get location(){return d},createHref:x,push:y,
31
- replace:w,go:p,back:function(){p(-1);},forward:function(){p(1);},listen:function(a){return f.push(a)},block:function(a){var e=c.push(a);1===c.length&&m.addEventListener("beforeunload",E);return function(){e();c.length||m.removeEventListener("beforeunload",E);}}}}
24
+ function createBrowserHistory(b){function h(){var c=p.location,a=m.state||{};return [a.idx,C({pathname:c.pathname,search:c.search,hash:c.hash,state:a.usr||null,key:a.key||"default"})]}function k(c){return "string"===typeof c?c:I(c)}function x(c,a){void 0===a&&(a=null);return C(_extends({pathname:q.pathname,hash:"",search:""},"string"===typeof c?J(c):c,{state:a,key:H()}))}function z(c){t=c;c=h();v=c[0];q=c[1];d.call({action:t,location:q});}function A(c,a){function e(){A(c,a);}var l=r.Push,g=x(c,
25
+ a);if(!f.length||(f.call({action:l,location:g,retry:e}),!1)){var n=[{usr:g.state,key:g.key,idx:v+1},k(g)];g=n[0];n=n[1];try{m.pushState(g,"",n);}catch(G){p.location.assign(n);}z(l);}}function y(c,a){function e(){y(c,a);}var l=r.Replace,g=x(c,a);f.length&&(f.call({action:l,location:g,retry:e}),1)||(g=[{usr:g.state,key:g.key,idx:v},k(g)],m.replaceState(g[0],"",g[1]),z(l));}function w(c){m.go(c);}void 0===b&&(b={});b=b.window;var p=void 0===b?document.defaultView:b,m=p.history,u=null;p.addEventListener("popstate",
26
+ function(){if(u)f.call(u),u=null;else {var c=r.Pop,a=h(),e=a[0];a=a[1];if(f.length)if(null!=e){var l=v-e;l&&(u={action:c,location:a,retry:function(){w(-1*l);}},w(l));}else "production"!==process.env.NODE_ENV?D(!1,"You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."):
27
+ void 0;else z(c);}});var t=r.Pop;b=h();var v=b[0],q=b[1],d=F(),f=F();null==v&&(v=0,m.replaceState(_extends({},m.state,{idx:v}),""));return {get action(){return t},get location(){return q},createHref:k,push:A,replace:y,go:w,back:function(){w(-1);},forward:function(){w(1);},listen:function(c){return d.push(c)},block:function(c){var a=f.push(c);1===f.length&&p.addEventListener("beforeunload",E);return function(){a();f.length||p.removeEventListener("beforeunload",E);}}}}function createHashHistory(b){function h(){var a=J(m.location.hash.substr(1)),e=a.pathname,l=a.search;a=a.hash;var g=u.state||{};return [g.idx,C({pathname:void 0===e?"/":e,search:void 0===l?"":l,hash:void 0===a?"":a,state:g.usr||null,key:g.key||"default"})]}function k(){if(t)c.call(t),t=null;else {var a=r.Pop,e=h(),l=e[0];e=e[1];if(c.length)if(null!=l){var g=q-l;g&&(t={action:a,location:e,retry:function(){p(-1*g);}},p(g));}else "production"!==process.env.NODE_ENV?D(!1,"You are trying to block a POP navigation to a location that was not created by the history library. The block will fail silently in production, but in general you should do all navigation with the history library (instead of using window.history.pushState directly) to avoid this situation."):
28
+ void 0;else A(a);}}function x(a){var e=document.querySelector("base"),l="";e&&e.getAttribute("href")&&(e=m.location.href,l=e.indexOf("#"),l=-1===l?e:e.slice(0,l));return l+"#"+("string"===typeof a?a:I(a))}function z(a,e){void 0===e&&(e=null);return C(_extends({pathname:d.pathname,hash:"",search:""},"string"===typeof a?J(a):a,{state:e,key:H()}))}function A(a){v=a;a=h();q=a[0];d=a[1];f.call({action:v,location:d});}function y(a,e){function l(){y(a,e);}var g=r.Push,n=z(a,e);"production"!==process.env.NODE_ENV?
29
+ D("/"===n.pathname.charAt(0),"Relative pathnames are not supported in hash history.push("+JSON.stringify(a)+")"):void 0;if(!c.length||(c.call({action:g,location:n,retry:l}),!1)){var G=[{usr:n.state,key:n.key,idx:q+1},x(n)];n=G[0];G=G[1];try{u.pushState(n,"",G);}catch(K){m.location.assign(G);}A(g);}}function w(a,e){function l(){w(a,e);}var g=r.Replace,n=z(a,e);"production"!==process.env.NODE_ENV?D("/"===n.pathname.charAt(0),"Relative pathnames are not supported in hash history.replace("+JSON.stringify(a)+
30
+ ")"):void 0;c.length&&(c.call({action:g,location:n,retry:l}),1)||(n=[{usr:n.state,key:n.key,idx:q},x(n)],u.replaceState(n[0],"",n[1]),A(g));}function p(a){u.go(a);}void 0===b&&(b={});b=b.window;var m=void 0===b?document.defaultView:b,u=m.history,t=null;m.addEventListener("popstate",k);m.addEventListener("hashchange",function(){var a=h()[1];I(a)!==I(d)&&k();});var v=r.Pop;b=h();var q=b[0],d=b[1],f=F(),c=F();null==q&&(q=0,u.replaceState(_extends({},u.state,{idx:q}),""));return {get action(){return v},get location(){return d},
31
+ createHref:x,push:y,replace:w,go:p,back:function(){p(-1);},forward:function(){p(1);},listen:function(a){return f.push(a)},block:function(a){var e=c.push(a);1===c.length&&m.addEventListener("beforeunload",E);return function(){e();c.length||m.removeEventListener("beforeunload",E);}}}}
32
32
 
33
33
  let history;
34
34
  let basename = '/';
@@ -47,9 +47,61 @@ 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
+ getLastIndex(pathname) {
80
+ const list = [...this.stacks].reverse();
81
+ return list.findIndex(page => { var _a; return ((_a = page.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname; });
82
+ }
83
+ getDelta(pathname) {
84
+ if (this.backDelta >= 1) {
85
+ return this.backDelta;
86
+ }
87
+ // NOTE: 此处为了修复浏览器后退多级页面,在大量重复路由状况下可能出现判断错误的情况 (增强判断能力只能考虑在 query 中新增参数来判断,暂时搁置)
88
+ return this.getLastIndex(pathname) || 1;
89
+ }
90
+ getPrevIndex(pathname) {
91
+ const lastIndex = this.getLastIndex(pathname);
92
+ if (lastIndex < 0) {
93
+ return -1;
94
+ }
95
+ return this.length - 1 - lastIndex;
96
+ }
97
+ pop() {
98
+ return this.stacks.pop();
99
+ }
100
+ push(page) {
101
+ return this.stacks.push(page);
102
+ }
103
+ }
104
+ const stacks = new Stacks();
53
105
 
54
106
  let routesAlias = {};
55
107
  function setRoutesAlias(alias) {
@@ -61,25 +113,6 @@ function addLeadingSlash(path) {
61
113
  }
62
114
  return path.charAt(0) === '/' ? path : '/' + path;
63
115
  }
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
116
  const isTabBar = (config) => {
84
117
  var _a, _b;
85
118
  const { customRoutes = {}, basename = '', pathname } = config.router;
@@ -89,6 +122,7 @@ const isTabBar = (config) => {
89
122
  };
90
123
 
91
124
  function processNavigateUrl(option) {
125
+ var _a;
92
126
  const pathPieces = J(option.url);
93
127
  // 处理自定义路由
94
128
  Object.keys(routesAlias).forEach(key => {
@@ -96,6 +130,18 @@ function processNavigateUrl(option) {
96
130
  pathPieces.pathname = routesAlias[key];
97
131
  }
98
132
  });
133
+ // 处理相对路径
134
+ if ((_a = pathPieces === null || pathPieces === void 0 ? void 0 : pathPieces.pathname) === null || _a === void 0 ? void 0 : _a.includes('./')) {
135
+ const parts = history.location.pathname.split('/');
136
+ parts.pop();
137
+ pathPieces.pathname.split('/').forEach((item) => {
138
+ if (item === '.') {
139
+ return;
140
+ }
141
+ item === '..' ? parts.pop() : parts.push(item);
142
+ });
143
+ pathPieces.pathname = parts.join('/');
144
+ }
99
145
  // 处理 basename
100
146
  pathPieces.pathname = prependBasename(pathPieces.pathname);
101
147
  // hack fix history v5 bug: https://github.com/remix-run/history/issues/814
@@ -103,41 +149,36 @@ function processNavigateUrl(option) {
103
149
  pathPieces.search = '';
104
150
  return pathPieces;
105
151
  }
106
- function navigate(option, method) {
107
- const { success, complete, fail } = option;
108
- let failReason;
109
- try {
110
- if ('url' in option) {
111
- const pathPieces = processNavigateUrl(option);
112
- const state = { timestamp: Date.now() };
113
- if (method === 'navigateTo') {
114
- history.push(pathPieces, state);
152
+ async function navigate(option, method) {
153
+ return new Promise((resolve, reject) => {
154
+ const { success, complete, fail } = option;
155
+ const unListen = history.listen(() => {
156
+ success === null || success === void 0 ? void 0 : success();
157
+ complete === null || complete === void 0 ? void 0 : complete();
158
+ resolve();
159
+ unListen();
160
+ });
161
+ try {
162
+ if ('url' in option) {
163
+ const pathPieces = processNavigateUrl(option);
164
+ const state = { timestamp: Date.now() };
165
+ if (method === 'navigateTo') {
166
+ history.push(pathPieces, state);
167
+ }
168
+ else if (method === 'redirectTo') {
169
+ history.replace(pathPieces, state);
170
+ }
115
171
  }
116
- else if (method === 'redirectTo') {
117
- history.replace(pathPieces, state);
172
+ else if (method === 'navigateBack') {
173
+ stacks.delta = option.delta;
174
+ history.go(-option.delta);
118
175
  }
119
176
  }
120
- else if (method === 'navigateBack') {
121
- setHistoryBackDelta(option.delta);
122
- history.go(-option.delta);
123
- }
124
- }
125
- catch (error) {
126
- failReason = error;
127
- }
128
- return new Promise((resolve, reject) => {
129
- if (failReason) {
130
- fail && fail(failReason);
131
- complete && complete();
132
- reject(failReason);
133
- return;
177
+ catch (error) {
178
+ fail === null || fail === void 0 ? void 0 : fail(error);
179
+ complete === null || complete === void 0 ? void 0 : complete();
180
+ reject(error);
134
181
  }
135
- const unlisten = history.listen(() => {
136
- success && success();
137
- complete && complete();
138
- resolve();
139
- unlisten();
140
- });
141
182
  });
142
183
  }
143
184
  function navigateTo(option) {
@@ -161,7 +202,7 @@ function reLaunch(option) {
161
202
  return redirectTo(option);
162
203
  }
163
204
  function getCurrentPages() {
164
- return stacks;
205
+ return stacks.get();
165
206
  }
166
207
 
167
208
  /**
@@ -807,6 +848,7 @@ var UniversalRouter = function () {
807
848
 
808
849
  UniversalRouter.pathToRegexp = pathToRegexp_1;
809
850
 
851
+ const Taro = require('@tarojs/taro-h5');
810
852
  function initTabbar(config) {
811
853
  if (config.tabBar == null) {
812
854
  return;
@@ -818,7 +860,6 @@ function initTabbar(config) {
818
860
  tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
819
861
  const routerConfig = config.router;
820
862
  tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
821
- tabbar.conf.custom = !!routerConfig.customRoutes;
822
863
  if (routerConfig.customRoutes) {
823
864
  tabbar.conf.custom = true;
824
865
  tabbar.conf.customRoutes = routerConfig.customRoutes;
@@ -833,6 +874,7 @@ function initTabbar(config) {
833
874
  const container = document.getElementById('container');
834
875
  // eslint-disable-next-line no-unused-expressions
835
876
  container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
877
+ Taro.initTabBarApis(config);
836
878
  }
837
879
 
838
880
  const routerConfig = Object.create(null);
@@ -856,6 +898,58 @@ function init(config) {
856
898
  initTabbar(config);
857
899
  }
858
900
 
901
+ let pageScrollFn;
902
+ let pageDOM = window;
903
+ function bindPageScroll(page, config) {
904
+ pageDOM.removeEventListener('scroll', pageScrollFn);
905
+ pageDOM = getScrollContainer();
906
+ const distance = config.onReachBottomDistance || 50;
907
+ let isReachBottom = false;
908
+ pageScrollFn = function () {
909
+ page.onPageScroll && page.onPageScroll({
910
+ scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
911
+ });
912
+ if (isReachBottom && getOffset() > distance) {
913
+ isReachBottom = false;
914
+ }
915
+ if (page.onReachBottom &&
916
+ !isReachBottom &&
917
+ getOffset() < distance) {
918
+ isReachBottom = true;
919
+ page.onReachBottom();
920
+ }
921
+ };
922
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
923
+ }
924
+ window.addEventListener('DOMSubtreeModified', (e) => {
925
+ var _a;
926
+ // @ts-ignore
927
+ const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
928
+ if (className && /taro-tabbar__/.test(className)) {
929
+ pageDOM.removeEventListener('scroll', pageScrollFn);
930
+ pageDOM = getScrollContainer();
931
+ pageDOM.addEventListener('scroll', pageScrollFn, false);
932
+ }
933
+ }, false);
934
+ function getScrollContainer() {
935
+ if (document.querySelector('.taro-tabbar__tabbar') === null) {
936
+ // 没设置tabbar
937
+ return window;
938
+ }
939
+ else {
940
+ // 有设置tabbar
941
+ return document.querySelector('.taro-tabbar__panel') || window;
942
+ }
943
+ }
944
+ function getOffset() {
945
+ if (pageDOM instanceof Window) {
946
+ return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
947
+ }
948
+ else {
949
+ return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
950
+ }
951
+ }
952
+
859
953
  function createCommonjsModule(fn, module) {
860
954
  return module = { exports: {} }, fn(module, module.exports), module.exports;
861
955
  }
@@ -1407,12 +1501,23 @@ var queryString_5 = queryString.stringifyUrl;
1407
1501
  var queryString_6 = queryString.pick;
1408
1502
  var queryString_7 = queryString.exclude;
1409
1503
 
1504
+ function getSearch() {
1505
+ let search = '?';
1506
+ if (routerConfig.router.mode === 'hash') {
1507
+ const idx = location.hash.indexOf('?');
1508
+ if (idx > -1) {
1509
+ search = location.hash.slice(idx);
1510
+ }
1511
+ }
1512
+ else {
1513
+ search = location.search;
1514
+ }
1515
+ return search.substr(1);
1516
+ }
1410
1517
  const qs = function (stamp = 0) {
1411
- const search = routerConfig.router.mode === 'hash'
1412
- ? location.hash.slice(routerConfig.router.pathname.length + 1)
1413
- : location.search;
1518
+ const search = getSearch();
1414
1519
  const query = search
1415
- ? queryString.parse(search.substr(1))
1520
+ ? queryString.parse(search)
1416
1521
  : {};
1417
1522
  if (stamp) {
1418
1523
  query.stamp = stamp.toString();
@@ -1420,95 +1525,13 @@ const qs = function (stamp = 0) {
1420
1525
  return query;
1421
1526
  };
1422
1527
 
1423
- let pageScrollFn;
1424
- let pageDOM = window;
1425
- function bindPageScroll(page, config) {
1426
- pageDOM.removeEventListener('scroll', pageScrollFn);
1427
- pageDOM = getScrollContainer();
1428
- const distance = config.onReachBottomDistance || 50;
1429
- let isReachBottom = false;
1430
- pageScrollFn = function () {
1431
- page.onPageScroll && page.onPageScroll({
1432
- scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
1433
- });
1434
- if (isReachBottom && getOffset() > distance) {
1435
- isReachBottom = false;
1436
- }
1437
- if (page.onReachBottom &&
1438
- !isReachBottom &&
1439
- getOffset() < distance) {
1440
- isReachBottom = true;
1441
- page.onReachBottom();
1442
- }
1443
- };
1444
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1445
- }
1446
- window.addEventListener('DOMSubtreeModified', (e) => {
1447
- var _a;
1448
- // @ts-ignore
1449
- const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
1450
- if (className && /taro-tabbar__/.test(className)) {
1451
- pageDOM.removeEventListener('scroll', pageScrollFn);
1452
- pageDOM = getScrollContainer();
1453
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1454
- }
1455
- }, false);
1456
- function getScrollContainer() {
1457
- if (document.querySelector('.taro-tabbar__tabbar') === null) {
1458
- // 没设置tabbar
1459
- return window;
1460
- }
1461
- else {
1462
- // 有设置tabbar
1463
- return document.querySelector('.taro-tabbar__panel') || window;
1464
- }
1465
- }
1466
- function getOffset() {
1467
- if (pageDOM instanceof Window) {
1468
- return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
1469
- }
1470
- else {
1471
- return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
1472
- }
1473
- }
1474
-
1475
1528
  /* eslint-disable dot-notation */
1476
- function hidePage(page) {
1477
- if (page != null) {
1478
- page.onHide();
1479
- const pageEl = document.getElementById(page.path);
1480
- if (pageEl) {
1481
- pageEl.style.display = 'none';
1482
- }
1483
- }
1484
- }
1485
- function showPage(page, pageConfig, stacksIndex = 0) {
1486
- if (page != null) {
1487
- page.onShow();
1488
- let pageEl = document.getElementById(page.path);
1489
- if (pageEl) {
1490
- pageEl.style.display = 'block';
1491
- }
1492
- else {
1493
- page.onLoad(qs(stacksIndex));
1494
- pageEl = document.getElementById(page.path);
1495
- pageOnReady(pageEl, page, false);
1496
- }
1497
- bindPageScroll(page, pageConfig || {});
1498
- }
1499
- }
1500
- function unloadPage(page) {
1501
- if (page != null) {
1502
- stacks.pop();
1503
- page.onUnload();
1504
- }
1505
- }
1506
- function pageOnReady(pageEl, page, onLoad = true) {
1507
- var _a;
1529
+ function pageOnReady(page, onLoad = true) {
1530
+ var _a, _b;
1531
+ const pageEl = document.getElementById(page.path);
1508
1532
  if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1509
1533
  const el = pageEl.firstElementChild;
1510
- // eslint-disable-next-line no-unused-expressions
1511
- (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el).then(() => {
1534
+ (_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(() => {
1512
1535
  requestAnimationFrame(() => {
1513
1536
  page.onReady();
1514
1537
  pageEl['__isReady'] = true;
@@ -1517,23 +1540,57 @@ function pageOnReady(pageEl, page, onLoad = true) {
1517
1540
  onLoad && (pageEl['__page'] = page);
1518
1541
  }
1519
1542
  }
1520
- function loadPage(page, pageConfig, stacksIndex = 0) {
1521
- if (page !== null) {
1522
- let pageEl = document.getElementById(page.path);
1523
- if (pageEl) {
1524
- pageEl.style.display = 'block';
1525
- }
1526
- else {
1527
- page.onLoad(qs(stacksIndex), function () {
1528
- pageEl = document.getElementById(page.path);
1529
- pageOnReady(pageEl, page);
1530
- });
1531
- }
1532
- stacks.push(page);
1533
- page.onShow();
1534
- bindPageScroll(page, pageConfig || {});
1543
+ function loadPage(page, pageConfig = {}, stacksIndex = 0) {
1544
+ if (!page)
1545
+ return;
1546
+ const pageEl = document.getElementById(page.path);
1547
+ if (pageEl) {
1548
+ pageEl.style.display = 'block';
1549
+ }
1550
+ else {
1551
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, true));
1552
+ }
1553
+ stacks.push(page);
1554
+ page.onShow();
1555
+ bindPageScroll(page, pageConfig);
1556
+ }
1557
+ function unloadPage(page, delta = 1) {
1558
+ if (!page)
1559
+ return;
1560
+ stacks.delta = --delta;
1561
+ stacks.pop();
1562
+ page.onUnload();
1563
+ if (delta >= 1)
1564
+ unloadPage(stacks.last, delta);
1565
+ }
1566
+ function showPage(page, pageConfig = {}, stacksIndex = 0) {
1567
+ if (!page)
1568
+ return;
1569
+ page.onShow();
1570
+ const pageEl = document.getElementById(page.path);
1571
+ if (pageEl) {
1572
+ pageEl.style.display = 'block';
1535
1573
  }
1574
+ else {
1575
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, false));
1576
+ }
1577
+ bindPageScroll(page, pageConfig);
1536
1578
  }
1579
+ function hidePage(page) {
1580
+ if (!page)
1581
+ return;
1582
+ // NOTE: 修复多页并发问题,此处可能因为路由跳转过快,执行时页面可能还没有创建成功
1583
+ const pageEl = document.getElementById(page.path);
1584
+ if (pageEl) {
1585
+ pageEl.style.display = 'none';
1586
+ page.onHide();
1587
+ }
1588
+ else {
1589
+ setTimeout(() => hidePage(page), 0);
1590
+ }
1591
+ }
1592
+
1593
+ /* eslint-disable dot-notation */
1537
1594
  function createRouter(app, config, framework) {
1538
1595
  var _a;
1539
1596
  init(config);
@@ -1552,7 +1609,7 @@ function createRouter(app, config, framework) {
1552
1609
  const basename = config.router.basename;
1553
1610
  const router = new UniversalRouter(routes, { baseUrl: basename || '' });
1554
1611
  app.onLaunch();
1555
- const render = throttle(async ({ location, action }) => {
1612
+ const render = async ({ location, action }) => {
1556
1613
  var _a, _b, _c, _d;
1557
1614
  routerConfig.router.pathname = location.pathname;
1558
1615
  let element;
@@ -1585,65 +1642,49 @@ function createRouter(app, config, framework) {
1585
1642
  document.title = (_b = pageConfig.navigationBarTitleText) !== null && _b !== void 0 ? _b : document.title;
1586
1643
  enablePullDownRefresh = pageConfig.enablePullDownRefresh;
1587
1644
  }
1645
+ const currentPage = Current.page;
1646
+ const pathname = location.pathname;
1588
1647
  let shouldLoad = false;
1589
1648
  if (action === 'POP') {
1590
- unloadPage(Current.page);
1591
- let delta = historyBackDelta;
1592
- while (delta-- > 1) {
1593
- unloadPage(stacks.slice(-1)[0]);
1594
- }
1595
- // 最终必须重置为 1
1596
- setHistoryBackDelta(1);
1597
- const prevIndex = stacks.reduceRight((p, s, i) => {
1598
- if (p !== 0)
1599
- return p;
1600
- else if (s.path === location.pathname + stringify(qs(i)))
1601
- return i;
1602
- else
1603
- return 0;
1604
- }, 0);
1605
- const prev = stacks[prevIndex];
1606
- if (prev) {
1607
- showPage(prev, pageConfig, prevIndex);
1649
+ // NOTE: 浏览器事件退后多次时,该事件只会被触发一次
1650
+ const prevIndex = stacks.getPrevIndex(pathname);
1651
+ const delta = stacks.getDelta(pathname);
1652
+ unloadPage(currentPage, delta);
1653
+ if (prevIndex > -1) {
1654
+ showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1608
1655
  }
1609
1656
  else {
1610
1657
  shouldLoad = true;
1611
1658
  }
1612
1659
  }
1613
1660
  else if (action === 'PUSH') {
1614
- hidePage(Current.page);
1661
+ hidePage(currentPage);
1615
1662
  shouldLoad = true;
1616
1663
  }
1617
1664
  else if (action === 'REPLACE') {
1618
1665
  if (isTabBar(config)) {
1619
- hidePage(Current.page);
1620
- const pathname = stripBasename(config.router.pathname, basename);
1621
- const prevIndex = stacks.findIndex((r) => {
1622
- var _a;
1623
- return ((_a = r.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname;
1624
- });
1666
+ hidePage(currentPage);
1667
+ const prevIndex = stacks.getPrevIndex(pathname);
1625
1668
  if (prevIndex > -1) {
1626
- // tabbar 页且之前出现过,直接复用
1627
- const prev = stacks[prevIndex];
1628
- return showPage(prev, pageConfig, prevIndex);
1669
+ // NOTE: tabbar 页且之前出现过,直接复用
1670
+ return showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1629
1671
  }
1630
1672
  }
1631
1673
  else {
1632
- unloadPage(Current.page);
1674
+ unloadPage(currentPage);
1633
1675
  }
1634
1676
  shouldLoad = true;
1635
1677
  }
1636
- if (shouldLoad) {
1678
+ if (shouldLoad || stacks.length < 1) {
1637
1679
  const el = (_c = element.default) !== null && _c !== void 0 ? _c : element;
1638
1680
  const loadConfig = Object.assign({}, pageConfig);
1681
+ const stacksIndex = stacks.length;
1639
1682
  delete loadConfig['path'];
1640
1683
  delete loadConfig['load'];
1641
- const pathname = stripBasename(config.router.pathname, basename);
1642
- const routerIndex = stacks.length;
1643
- 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);
1644
- loadPage(page, pageConfig, routerIndex);
1684
+ 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);
1685
+ return loadPage(page, pageConfig, stacksIndex);
1645
1686
  }
1646
- }, 500);
1687
+ };
1647
1688
  if (history.location.pathname === '/') {
1648
1689
  history.replace(prependBasename(routes[0].path + history.location.search));
1649
1690
  }