concat.js
12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
import { warn, err } from '../helpers/warn';
import {
diffRouter, vueDevRouteProxy, getRouterNextInfo, formatUserRule, nameToRute, encodeURLQuery, strPathToObjPath, getPages,
} from './util';
import { formatURLQuery } from '../helpers/util';
import { vuelifeHooks, vueMount } from './base';
import { lifeCycle, Global } from '../helpers/config';
let beforeEachCount = 0;
let afterEachCount = 0;
let resolveLaunch = null;
let beforeEnterDep = [];// 记录当前是否有重复的页面进入 避免重复触发
const beforeEachLaunch = new Promise((resolve) => resolveLaunch = resolve);
/**
* 把vue实例进行挂载到dom下
* @param {Router} Router uni-simple-router实例对象
*/
export const appMount = function () {
if (vueMount.length == 0) {
return err('检测到您未进行dom模型挂载操作,请调用api\r\n\r\n RouterMount(Vim: any, el: any): void');
}
const {
Vim,
el,
} = vueMount[0];
let formatEl = el;
if (el == null) {
formatEl = '#app'; // 这是uni-app在h5中的官方节点
}
try {
Vim.$mount(formatEl);
} catch (error) {
warn(`挂载vue节点时错误啦${error}`);
}
};
/**
* 格式化 next传递过来的参数 作为vue-router可用的
* @param {Object} to//即将跳转到的路由页面
* @param {*} Intercept
* @param {Funtion} next//路由连接管道
* @param {Router} Router//路由对象
*/
export const forMatNext = function (to, Intercept, next, Router) {
const { CONFIG, selfRoutes } = Router;
if (CONFIG.h5.vueRouterDev) { // 完全使用vue-router开发的时候 vueRouterDev:true 不用做啥直接略过
next(Intercept);
return Intercept;
}
if (typeof Intercept === 'object') { // 只有是对象类型的时候 我们才进行格式化
const navType = Reflect.get(Intercept, 'NAVTYPE');
delete Intercept.NAVTYPE;
if (navType == 'push') {
Intercept.replace = false;
Intercept.type = 'navigateTo';
} else {
Intercept.replace = true; // uni-app导航api所谓的NAVTYPE取值在h5都是replace:true
Intercept.type = 'reLaunch';
}
const name = Reflect.get(Intercept, 'name'); // 统一格式化path
Intercept.query = Intercept.params || Intercept.query;
delete Intercept.name;
delete Intercept.params;
if (Intercept.query == null) {
Intercept.query = {};
}
if (name != null) {
const { aliasPath, path } = nameToRute(name, selfRoutes);
Intercept.path = aliasPath || path;
} else { // 当设置别名时可以是别名跳转也可以path跳转
Intercept.path = Reflect.get(Intercept, 'path');
const rute = formatUserRule(Intercept.path, selfRoutes, CONFIG);
if (rute == null) {
return false;
}
Intercept.path = rute;
}
if (CONFIG.encodeURI) { // 如果设置的编码传递则进行编码后传递
const query = encodeURIComponent(JSON.stringify(Intercept.query));
const formatQuery = formatURLQuery(query);
Intercept.query = {};
if (formatQuery != '') {
Intercept.query.query = formatQuery;
}
}
} else if (Intercept != null && Intercept.constructor === String) {
Intercept = formatUserRule(Intercept, selfRoutes, CONFIG);
}
let objPath = Intercept;
if (Intercept != null && Intercept.constructor !== Boolean) {
objPath = strPathToObjPath(Intercept);
if (objPath != null) {
const type = Reflect.get(objPath, 'type');
if (type == null) { // 当next()是一个路径时
objPath.type = 'navigateTo';
}
}
} else if (Intercept === false) {
Router.lifeCycle.routerAfterHooks[0].call(Router, { H5Intercept: true });
}
next(objPath);// 统一格式化为对象的方式传递
return Intercept;
};
/**
* v1.5.4+
* beforeRouteLeave 生命周期
* @param {Object} to 将要去的那个页面 vue-router to对象
* @param {Object} from 从那个页面触发的 vue-router from对象
* @param {Object} next vue-router beforeEach next管道函数
* @param {Object} Router Router路由对象
*/
const beforeRouteLeaveHooks = function (to, from, next, Router) {
return new Promise((resolve) => {
const { currentRoute } = Router.$route;
if (currentRoute.path == to.path) { // 如果是同一个页面直接返回 不执行页面中的Leave事件
return resolve();
}
const page = getPages(); // 获取到当前的页面对象
if (page == null || page._HHYANGbeforeRouteLeaveCalled) {
warn('当前环境下无须执行 beforeRouteLeave。 原因:1.page等于null 2.真的的无须执行');
return resolve();
}
const beforeRouteLeaveArray = page.$options.beforeRouteLeave; // 获取到页面下的 beforeRouteLeave 路由守卫
if (beforeRouteLeaveArray == null) { // 当前页面没有预设 beforeRouteLeave 啥都不做
return resolve();
}
const { toRoute, fromRoute } = getRouterNextInfo(to, from, Router);
const beforeRouteLeave = beforeRouteLeaveArray[0]; // 不管怎么样 只执行第一个钩子 其他都不管
beforeRouteLeave.call(page, toRoute, fromRoute, (Intercept) => { // 开始执行生命周期
if (Intercept == null) { // 放行状态 直接返回
return resolve();
}
page._HHYANGbeforeRouteLeaveCalled = true; // 标记一下当前已经做过 beforeRouteLeave 啦
forMatNext(to, Intercept, next, Router); // 直接交给vue-router 处理
});
});
};
/**
* 修复首页beforeEnter执行两次的问题 https://github.com/SilurianYang/uni-simple-router/issues/67
*
* beforeEnter 生命周期
* @param {Object} to
* @param {Object} from
* @param {Object} next
* @param {Object} userHooks
* @param {Object} Router
*/
export const beforeEnterHooks = function (to, from, next, userHooks, Router) {
return new Promise(async (resolve) => {
// 修复 (#67)
if (beforeEnterDep.includes(to.path)) {
next();
return resolve();
}
beforeEnterDep = [to.path];
if (Reflect.get(Router, 'H5RouterReady')) {
const res = await new Promise(async (resolveNext) => {
const {
toRoute,
fromRoute,
} = getRouterNextInfo(to, from, Router);
await userHooks(toRoute, fromRoute, resolveNext);
});
forMatNext(to, res, next, Router);
} else {
next();
}
resolve();
});
};
/**
* vueAfter 生命周期
* @param {Object} to
* @param {Object} from
* @param {Object} next
* @param {Object} Router
*/
export const afterHooks = async function (to, from, next, Router) {
vuelifeHooks.afterHooks[0](to, from);
if (lifeCycle.afterHooks[0]) {
if (afterEachCount === 0) {
await beforeEachLaunch;
appMount(Router);
}
const {
toRoute,
fromRoute,
} = getRouterNextInfo(to, from, Router);
lifeCycle.afterHooks[0](toRoute, fromRoute);
} else if (afterEachCount === 0) {
appMount(Router);
}
afterEachCount += 1;
Router.lifeCycle.routerAfterHooks[0].call(Router);
};
/**
* vueBefore 生命周期
* @param {Object} to 将要去的那个页面 vue-router to对象
* @param {Object} from 从那个页面触发的 vue-router from对象
* @param {Object} next vue-router beforeEach next管道函数
* @param {Object} H5Config
*/
export const beforeHooks = function (to, from, next, Router) {
return new Promise(async (resolve) => {
await Router.lifeCycle.routerbeforeHooks[0].call(Router); // 触发Router内置前置生命周期
await beforeRouteLeaveHooks(to, from, next, Router); // 执行1.5.4+ beforeRouteLeave生命钩子
const H5 = Router.CONFIG.h5;
vuelifeHooks.beforeHooks[0](to, from, async (Intercept) => {
if (Intercept != null && H5.keepUniIntercept === true && H5.vueRouterDev === false) {
next(Intercept);
warn('uni-app 内部强制触发跳转拦截');
beforeEachCount += 1;
return resolve();
}
// 顺序问题 没有触发uni-app里面的方法 修复[#44](https://github.com/SilurianYang/uni-simple-router/issues/44)
if (!lifeCycle.beforeHooks[0]) {
next();
beforeEachCount += 1;
resolveLaunch();
return resolve();
}
const res = await new Promise(async (resolveNext) => {
const {
toRoute,
fromRoute,
} = getRouterNextInfo(to, from, Router);
await lifeCycle.beforeHooks[0](toRoute, fromRoute, resolveNext);
});
const beforeIntercept = forMatNext(to, res, next, Router);
if (beforeEachCount == 0 && beforeIntercept == null && to.meta.isTabBar) { // 首次触发beforeEach,并且首页没有进行跳转的情况下才触发beforeEnter 主要是keep-alive
const {
selfRoutes,
} = Router;
const beforeEnter = Reflect.get(selfRoutes[`/${to.meta.pagePath}`], 'beforeEnter');
if (beforeEnter) {
await beforeEnterHooks(to, from, next, beforeEnter, Router);
}
}
beforeEachCount += 1;
resolveLaunch();
resolve();
});
});
};
/**
* 通过自动调用router api来完成触发生命周期
* 修复 history 模式下报错的问题 https://github.com/SilurianYang/uni-simple-router/issues/38
* 修复 history 模式下刷新页面参数丢失的问题 https://github.com/SilurianYang/uni-simple-router/issues/45
* 修复 history 模式下首次打开页面url错误时不走 path:* 的匹配项 https://github.com/SilurianYang/uni-simple-router/issues/58
*
* @param {Object} Router //当前simple-router 对象
* @param {Object} vueRouter vue-router对象
*/
export const triggerLifeCycle = function (Router, vueRouter) {
const { CONFIG } = Router;
const currRoute = vueRouter.currentRoute;
if (vueRouter.mode === 'hash') {
const {
query,
path,
} = currRoute;
const URLQuery = encodeURLQuery(CONFIG, query, 'hash');
vueRouter.replace(`${path}${URLQuery}`);
} else {
const {
toRoute,
} = getRouterNextInfo(currRoute, currRoute, Router);
const URLQuery = encodeURLQuery(CONFIG, currRoute.query, 'history');
vueRouter.replace({
path: toRoute.aliasPath || toRoute.path || currRoute.path,
query: URLQuery,
type: 'redirectTo',
});
}
};
/** 注册自定义的路由到vue-router中 前提是必须使用vueRouter开发模式
* @param {Object} Router
* @param {Object} vueRouter
* @param {Boolean} vueRouterDev
*/
export const registerRouter = function (Router, vueRouter, vueRouterDev) {
let routeMap = [];
if (!vueRouterDev) { // 则进行对比两个路由表 主要工作是做路径的优化
routeMap = diffRouter(Router, vueRouter, Router.CONFIG.h5.useUniConfig);
} else { // 完全使用vue-router开发时直接采用开发者的路由表
routeMap = vueDevRouteProxy(Router.CONFIG.routes, Router);
}
const createRouter = () => new vueRouter.constructor({
base: vueRouter.options.base,
mode: vueRouter.options.mode,
routes: routeMap,
});
const router = createRouter();
vueRouter.matcher = router.matcher;
Global.vueRouter = vueRouter; // 把当前vueRouter缓存到全局对象中
Global.RouterReadyPromise(); // router已经准备就绪 调用promise.resolve();
Router.H5RouterReady = true; // 并挂载到Router对象下
// 注册完成所有的钩子及相关参数,手动触发Router的生命周期
setTimeout(() => {
triggerLifeCycle(Router, vueRouter);
});
};