@tarojs/router 3.3.11 → 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) {
@@ -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 = '/';
@@ -45,11 +45,56 @@ function setHistoryMode(mode, base = '/') {
45
45
  history = createHashHistory(options);
46
46
  }
47
47
  }
48
- function parsePath(url = '') {
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,73 +106,72 @@ 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
- };
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);
81
115
  };
82
116
 
83
117
  function processNavigateUrl(option) {
84
- let url = option.url;
85
- const matches = option.url.match(/[?&?].*/);
86
- let parameters = '';
87
- if (matches && matches.length) {
88
- parameters = matches[0];
89
- url = url.replace(parameters, '');
90
- }
118
+ var _a;
119
+ const pathPieces = J(option.url);
120
+ // 处理自定义路由
91
121
  Object.keys(routesAlias).forEach(key => {
92
- if (addLeadingSlash(key) === addLeadingSlash(url)) {
93
- option.url = routesAlias[key] + parameters;
122
+ if (addLeadingSlash(key) === addLeadingSlash(pathPieces.pathname)) {
123
+ pathPieces.pathname = routesAlias[key];
94
124
  }
95
125
  });
96
- }
97
- function navigate(option, method) {
98
- const { success, complete, fail } = option;
99
- let failReason;
100
- if (option.url) {
101
- processNavigateUrl(option);
102
- }
103
- try {
104
- if (method === 'navigateTo') {
105
- history.push(parsePath(option.url), { timestamp: Date.now() });
106
- }
107
- else if (method === 'redirectTo') {
108
- history.replace(parsePath(option.url), { timestamp: Date.now() });
109
- }
110
- else if (method === 'navigateBack') {
111
- setHistoryBackDelta(option.delta);
112
- history.go(-option.delta);
113
- }
114
- }
115
- catch (error) {
116
- failReason = error;
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('/');
117
137
  }
138
+ // 处理 basename
139
+ pathPieces.pathname = prependBasename(pathPieces.pathname);
140
+ // hack fix history v5 bug: https://github.com/remix-run/history/issues/814
141
+ if (!pathPieces.search)
142
+ pathPieces.search = '';
143
+ return pathPieces;
144
+ }
145
+ async function navigate(option, method) {
118
146
  return new Promise((resolve, reject) => {
119
- if (failReason) {
120
- fail && fail(failReason);
121
- complete && complete();
122
- reject(failReason);
123
- return;
124
- }
125
- const unlisten = history.listen(() => {
126
- success && success();
127
- complete && complete();
147
+ const { success, complete, fail } = option;
148
+ const unListen = history.listen(() => {
149
+ success === null || success === void 0 ? void 0 : success();
150
+ complete === null || complete === void 0 ? void 0 : complete();
128
151
  resolve();
129
- unlisten();
152
+ unListen();
130
153
  });
154
+ try {
155
+ if ('url' in option) {
156
+ const pathPieces = processNavigateUrl(option);
157
+ const state = { timestamp: Date.now() };
158
+ if (method === 'navigateTo') {
159
+ history.push(pathPieces, state);
160
+ }
161
+ else if (method === 'redirectTo') {
162
+ history.replace(pathPieces, state);
163
+ }
164
+ }
165
+ else if (method === 'navigateBack') {
166
+ stacks.delta = option.delta;
167
+ history.go(-option.delta);
168
+ }
169
+ }
170
+ catch (error) {
171
+ fail === null || fail === void 0 ? void 0 : fail(error);
172
+ complete === null || complete === void 0 ? void 0 : complete();
173
+ reject(error);
174
+ }
131
175
  });
132
176
  }
133
177
  function navigateTo(option) {
@@ -143,13 +187,15 @@ function navigateBack(options = { delta: 1 }) {
143
187
  return navigate(options, 'navigateBack');
144
188
  }
145
189
  function switchTab(option) {
146
- return navigateTo(option);
190
+ // TODO: 清除掉所有的栈去目标页面
191
+ return redirectTo(option);
147
192
  }
148
193
  function reLaunch(option) {
194
+ // TODO: 清除掉所有的栈去目标页面
149
195
  return redirectTo(option);
150
196
  }
151
197
  function getCurrentPages() {
152
- return stacks;
198
+ return stacks.get();
153
199
  }
154
200
 
155
201
  /**
@@ -795,6 +841,7 @@ var UniversalRouter = function () {
795
841
 
796
842
  UniversalRouter.pathToRegexp = pathToRegexp_1;
797
843
 
844
+ const Taro = require('@tarojs/taro-h5');
798
845
  function initTabbar(config) {
799
846
  if (config.tabBar == null) {
800
847
  return;
@@ -806,7 +853,6 @@ function initTabbar(config) {
806
853
  tabbar.conf.homePage = history.location.pathname === '/' ? homePage : history.location.pathname;
807
854
  const routerConfig = config.router;
808
855
  tabbar.conf.mode = routerConfig && routerConfig.mode ? routerConfig.mode : 'hash';
809
- tabbar.conf.custom = !!routerConfig.customRoutes;
810
856
  if (routerConfig.customRoutes) {
811
857
  tabbar.conf.custom = true;
812
858
  tabbar.conf.customRoutes = routerConfig.customRoutes;
@@ -815,9 +861,13 @@ function initTabbar(config) {
815
861
  tabbar.conf.custom = false;
816
862
  tabbar.conf.customRoutes = {};
817
863
  }
864
+ if (typeof routerConfig.basename !== 'undefined') {
865
+ tabbar.conf.basename = routerConfig.basename;
866
+ }
818
867
  const container = document.getElementById('container');
819
868
  // eslint-disable-next-line no-unused-expressions
820
869
  container === null || container === void 0 ? void 0 : container.appendChild(tabbar);
870
+ Taro.initTabBarApis(config);
821
871
  }
822
872
 
823
873
  const routerConfig = Object.create(null);
@@ -841,6 +891,58 @@ function init(config) {
841
891
  initTabbar(config);
842
892
  }
843
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
+
844
946
  function createCommonjsModule(fn, module) {
845
947
  return module = { exports: {} }, fn(module, module.exports), module.exports;
846
948
  }
@@ -1392,12 +1494,23 @@ var queryString_5 = queryString.stringifyUrl;
1392
1494
  var queryString_6 = queryString.pick;
1393
1495
  var queryString_7 = queryString.exclude;
1394
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
+ }
1395
1510
  const qs = function (stamp = 0) {
1396
- const search = routerConfig.router.mode === 'hash'
1397
- ? location.hash.slice(routerConfig.router.pathname.length + 1)
1398
- : location.search;
1511
+ const search = getSearch();
1399
1512
  const query = search
1400
- ? queryString.parse(search.substr(1))
1513
+ ? queryString.parse(search)
1401
1514
  : {};
1402
1515
  if (stamp) {
1403
1516
  query.stamp = stamp.toString();
@@ -1405,94 +1518,12 @@ const qs = function (stamp = 0) {
1405
1518
  return query;
1406
1519
  };
1407
1520
 
1408
- let pageScrollFn;
1409
- let pageDOM = window;
1410
- function bindPageScroll(page, config) {
1411
- pageDOM.removeEventListener('scroll', pageScrollFn);
1412
- pageDOM = getScrollContainer();
1413
- const distance = config.onReachBottomDistance || 50;
1414
- let isReachBottom = false;
1415
- pageScrollFn = function () {
1416
- page.onPageScroll && page.onPageScroll({
1417
- scrollTop: pageDOM instanceof Window ? window.scrollY : pageDOM.scrollTop
1418
- });
1419
- if (isReachBottom && getOffset() > distance) {
1420
- isReachBottom = false;
1421
- }
1422
- if (page.onReachBottom &&
1423
- !isReachBottom &&
1424
- getOffset() < distance) {
1425
- isReachBottom = true;
1426
- page.onReachBottom();
1427
- }
1428
- };
1429
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1430
- }
1431
- window.addEventListener('DOMSubtreeModified', (e) => {
1432
- var _a;
1433
- // @ts-ignore
1434
- const className = (_a = e.target) === null || _a === void 0 ? void 0 : _a.className;
1435
- if (className && /taro-tabbar__/.test(className)) {
1436
- pageDOM.removeEventListener('scroll', pageScrollFn);
1437
- pageDOM = getScrollContainer();
1438
- pageDOM.addEventListener('scroll', pageScrollFn, false);
1439
- }
1440
- }, false);
1441
- function getScrollContainer() {
1442
- if (document.querySelector('.taro-tabbar__tabbar') === null) {
1443
- // 没设置tabbar
1444
- return window;
1445
- }
1446
- else {
1447
- // 有设置tabbar
1448
- return document.querySelector('.taro-tabbar__panel') || window;
1449
- }
1450
- }
1451
- function getOffset() {
1452
- if (pageDOM instanceof Window) {
1453
- return document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
1454
- }
1455
- else {
1456
- return pageDOM.scrollHeight - pageDOM.scrollTop - pageDOM.clientHeight;
1457
- }
1458
- }
1459
-
1460
1521
  /* eslint-disable dot-notation */
1461
- function hidePage(page) {
1462
- if (page != null) {
1463
- page.onHide();
1464
- const pageEl = document.getElementById(page.path);
1465
- if (pageEl) {
1466
- pageEl.style.display = 'none';
1467
- }
1468
- }
1469
- }
1470
- function showPage(page, pageConfig, stacksIndex = 0) {
1471
- if (page != null) {
1472
- page.onShow();
1473
- let pageEl = document.getElementById(page.path);
1474
- if (pageEl) {
1475
- pageEl.style.display = 'block';
1476
- }
1477
- else {
1478
- page.onLoad(qs(stacksIndex));
1479
- pageEl = document.getElementById(page.path);
1480
- pageOnReady(pageEl, page, false);
1481
- }
1482
- bindPageScroll(page, pageConfig || {});
1483
- }
1484
- }
1485
- function unloadPage(page) {
1486
- if (page != null) {
1487
- stacks.pop();
1488
- page.onUnload();
1489
- }
1490
- }
1491
- function pageOnReady(pageEl, page, onLoad = true) {
1522
+ function pageOnReady(page, onLoad = true) {
1492
1523
  var _a;
1524
+ const pageEl = document.getElementById(page.path);
1493
1525
  if (pageEl && !(pageEl === null || pageEl === void 0 ? void 0 : pageEl['__isReady'])) {
1494
1526
  const el = pageEl.firstElementChild;
1495
- // eslint-disable-next-line no-unused-expressions
1496
1527
  (_a = el === null || el === void 0 ? void 0 : el['componentOnReady']) === null || _a === void 0 ? void 0 : _a.call(el).then(() => {
1497
1528
  requestAnimationFrame(() => {
1498
1529
  page.onReady();
@@ -1502,23 +1533,57 @@ function pageOnReady(pageEl, page, onLoad = true) {
1502
1533
  onLoad && (pageEl['__page'] = page);
1503
1534
  }
1504
1535
  }
1505
- function loadPage(page, pageConfig, stacksIndex = 0) {
1506
- if (page !== null) {
1507
- let pageEl = document.getElementById(page.path);
1508
- if (pageEl) {
1509
- pageEl.style.display = 'block';
1510
- }
1511
- else {
1512
- page.onLoad(qs(stacksIndex), function () {
1513
- pageEl = document.getElementById(page.path);
1514
- pageOnReady(pageEl, page);
1515
- });
1516
- }
1517
- stacks.push(page);
1518
- page.onShow();
1519
- 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';
1542
+ }
1543
+ else {
1544
+ page.onLoad(qs(stacksIndex), () => pageOnReady(page, true));
1520
1545
  }
1546
+ stacks.push(page);
1547
+ page.onShow();
1548
+ bindPageScroll(page, pageConfig);
1521
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)
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 */
1522
1587
  function createRouter(app, config, framework) {
1523
1588
  var _a;
1524
1589
  init(config);
@@ -1537,8 +1602,8 @@ function createRouter(app, config, framework) {
1537
1602
  const basename = config.router.basename;
1538
1603
  const router = new UniversalRouter(routes, { baseUrl: basename || '' });
1539
1604
  app.onLaunch();
1540
- const render = throttle(async ({ location, action }) => {
1541
- var _a, _b, _c, _d, _e;
1605
+ const render = async ({ location, action }) => {
1606
+ var _a, _b, _c, _d;
1542
1607
  routerConfig.router.pathname = location.pathname;
1543
1608
  let element;
1544
1609
  try {
@@ -1570,63 +1635,51 @@ function createRouter(app, config, framework) {
1570
1635
  document.title = (_b = pageConfig.navigationBarTitleText) !== null && _b !== void 0 ? _b : document.title;
1571
1636
  enablePullDownRefresh = pageConfig.enablePullDownRefresh;
1572
1637
  }
1638
+ const currentPage = Current.page;
1639
+ const pathname = location.pathname;
1573
1640
  let shouldLoad = false;
1574
1641
  if (action === 'POP') {
1575
- unloadPage(Current.page);
1576
- let delta = historyBackDelta;
1577
- while (delta-- > 1) {
1578
- unloadPage(stacks.slice(-1)[0]);
1579
- }
1580
- // 最终必须重置为 1
1581
- setHistoryBackDelta(1);
1582
- const prevIndex = stacks.reduceRight((p, s, i) => {
1583
- if (p !== 0)
1584
- return p;
1585
- else if (s.path === location.pathname + stringify(qs(i)))
1586
- return i;
1587
- else
1588
- return 0;
1589
- }, 0);
1590
- const prev = stacks[prevIndex];
1591
- if (prev) {
1592
- 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);
1593
1648
  }
1594
1649
  else {
1595
1650
  shouldLoad = true;
1596
1651
  }
1597
1652
  }
1598
1653
  else if (action === 'PUSH') {
1599
- hidePage(Current.page);
1654
+ hidePage(currentPage);
1600
1655
  shouldLoad = true;
1601
1656
  }
1602
1657
  else if (action === 'REPLACE') {
1603
- unloadPage(Current.page);
1658
+ if (isTabBar(config)) {
1659
+ hidePage(currentPage);
1660
+ const prevIndex = stacks.getPrevIndex(pathname);
1661
+ if (prevIndex > -1) {
1662
+ // NOTE: tabbar 页且之前出现过,直接复用
1663
+ return showPage(stacks.getItem(prevIndex), pageConfig, prevIndex);
1664
+ }
1665
+ }
1666
+ else {
1667
+ unloadPage(currentPage);
1668
+ }
1604
1669
  shouldLoad = true;
1605
1670
  }
1606
1671
  if (shouldLoad) {
1607
1672
  const el = (_c = element.default) !== null && _c !== void 0 ? _c : element;
1608
- const config = Object.assign({}, pageConfig);
1609
- delete config['path'];
1610
- delete config['load'];
1611
- const pathname = basename ? location.pathname.replace(basename, '') : location.pathname;
1612
- let routerIndex;
1613
- const isTabBar = (_d = routerConfig.tabBar) === null || _d === void 0 ? void 0 : _d.list.some((TabBarItem) => {
1614
- var _a;
1615
- return ((_a = TabBarItem.pagePath) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname;
1616
- });
1617
- if ((stacks === null || stacks === void 0 ? void 0 : stacks.length) > 0 && isTabBar) {
1618
- routerIndex = stacks.findIndex((r) => {
1619
- var _a;
1620
- return ((_a = r.path) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/g, '')) === pathname;
1621
- });
1622
- }
1623
- routerIndex = ((routerIndex || routerIndex === 0) && routerIndex !== -1) ? routerIndex : stacks.length;
1624
- const page = createPageConfig(enablePullDownRefresh ? (_e = runtimeHooks.createPullDownComponent) === null || _e === void 0 ? void 0 : _e.call(runtimeHooks, el, location.pathname, framework, routerConfig.PullDownRefresh) : el, pathname + stringify(qs(routerIndex)), {}, config);
1625
- loadPage(page, pageConfig, routerIndex);
1673
+ const loadConfig = Object.assign({}, pageConfig);
1674
+ const stacksIndex = stacks.length;
1675
+ delete loadConfig['path'];
1676
+ 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);
1626
1679
  }
1627
- }, 500);
1680
+ };
1628
1681
  if (history.location.pathname === '/') {
1629
- history.replace(parsePath(routes[0].path + history.location.search));
1682
+ history.replace(prependBasename(routes[0].path + history.location.search));
1630
1683
  }
1631
1684
  render({ location: history.location, action: r.Push });
1632
1685
  app.onShow(qs(stacks.length));