Forráskód Böngészése

优化 router,支持 isAuth,并添加示例

icssoa 6 hónapja
szülő
commit
3f988f2c31

+ 1 - 1
cool/ctx/index.ts

@@ -64,7 +64,7 @@ if (isArray(ctx.subPackages)) {
 			PAGES.push({
 				path: a.root + "/" + b.path, // 拼接子包根路径和页面路径
 				style: b.style,
-				meta: b.meta ?? {},
+				meta: b.meta
 			});
 		});
 	});

+ 85 - 49
cool/router/index.ts

@@ -1,11 +1,24 @@
 import { PAGES, TABS } from "../ctx";
 import type { BackOptions, PageInstance, PushOptions } from "../types";
-import { storage, last, isNull, isEmpty, get, isFunction, toArray, map, debounce } from "../utils";
+import {
+	storage,
+	last,
+	isNull,
+	isEmpty,
+	get,
+	isFunction,
+	toArray,
+	map,
+	debounce,
+	nth
+} from "../utils";
 
 // 路由信息类型
 type RouteInfo = {
 	path: string;
-	meta?: UTSJSONObject;
+	query: UTSJSONObject;
+	meta: UTSJSONObject;
+	isAuth?: boolean;
 };
 
 // 跳转前钩子类型
@@ -21,15 +34,11 @@ type Events = {
 
 // 路由核心类
 export class Router {
-	private _events = {} as Events; // 事件存储
+	private eventsMap = {} as Events; // 事件存储
 
 	// 获取缓存的路由参数
 	params() {
-		const data = storage.get("router-params") as UTSJSONObject;
-		if (isNull(data)) {
-			return {} as UTSJSONObject;
-		}
-		return data;
+		return (storage.get("router-params") ?? {}) as UTSJSONObject;
 	}
 
 	// 获取默认路径,支持 home 和 login
@@ -38,6 +47,7 @@ export class Router {
 			home: PAGES[0].path, // 首页为第一个页面
 			login: "/pages/user/login"
 		};
+
 		return get(paths, name) as string;
 	}
 
@@ -45,31 +55,38 @@ export class Router {
 	getPages(): PageInstance[] {
 		return map(getCurrentPages(), (e) => {
 			let path = e.route!;
+
 			// 根路径自动转为首页
 			if (path == "/") {
 				path = this.defaultPath("home");
 			}
+
 			// 补全路径前缀
 			if (!path.startsWith("/")) {
 				path = "/" + path;
 			}
+
 			// 获取页面样式
 			const page = PAGES.find((e) => e.path == path);
 			const style = page?.style;
 			const meta = page?.meta;
+
 			// 获取页面暴露的方法
 			// @ts-ignore
-			let exposed = e.vm as any;
+			const vm = e.vm as any;
+
+			let exposed = vm;
+
 			// #ifdef H5
 			exposed = get(e, "vm.$.exposed");
 			// #endif
+
 			// 获取页面 query 参数
 			const query = (get(e, "options") ?? {}) as UTSJSONObject;
+
 			return {
 				path,
-				// @ts-ignore
-				vm: e.vm!,
-				// @ts-ignore
+				vm,
 				exposed,
 				style,
 				meta,
@@ -113,7 +130,8 @@ export class Router {
 			complete,
 			animationType,
 			animationDuration,
-			events
+			events,
+			isAuth
 		} = options;
 
 		// 拼接 query 参数到 url
@@ -176,15 +194,15 @@ export class Router {
 		};
 
 		// 跳转前钩子处理
-		if (isFunction(this._events["beforeEach"])) {
-			const meta = PAGES.find((e) => e.path == path)?.meta;
-			const from = this.getPages().slice(-1)[0];
-			const to: RouteInfo = { path, meta: meta ?? {} };
-			(this._events["beforeEach"] as BeforeEach)(
-				to,
-				from,
-				next
-			);
+		if (this.eventsMap.beforeEach != null) {
+			// 当前页
+			const from = last(this.getPages());
+
+			// 跳转页
+			const to = { path, meta: this.getMeta(path), query, isAuth } as RouteInfo;
+
+			// 调用跳转前钩子
+			this.eventsMap.beforeEach(to, from!, next);
 		} else {
 			next();
 		}
@@ -197,31 +215,49 @@ export class Router {
 		});
 	}
 
-	// 返回上一页,若为首页则回首页
+	// 返回上一页
 	back(options: BackOptions | null = null) {
-		let path = ''
-		const next = ()=>{
-			if (this.isFirstPage()) {
-				this.home();
-				path = this.defaultPath("home")
-			} else {
-				path = this.getPages().slice(-2)[0].path;
+		if (this.isFirstPage()) {
+			this.home();
+		} else {
+			const delta = options?.delta ?? 1;
+
+			// 执行跳转函数
+			const next = () => {
 				uni.navigateBack({ ...(options ?? {}) });
+			};
+
+			// 跳转前钩子处理
+			if (this.eventsMap.beforeEach != null) {
+				// 当前页
+				const from = last(this.getPages());
+
+				// 上一页
+				const to = nth(this.getPages(), -delta - 1);
+
+				if (to != null) {
+					// 调用跳转前钩子
+					this.eventsMap.beforeEach(
+						{
+							path: to.path,
+							query: to.query,
+							meta: to.meta ?? ({} as UTSJSONObject)
+						},
+						from!,
+						next
+					);
+				} else {
+					console.error("[router] found to page is null");
+				}
+			} else {
+				next();
 			}
 		}
-		// 跳转前钩子处理
-		if (isFunction(this._events["beforeEach"])) {
-			const meta = PAGES.find((e) => e.path == path)?.meta;
-			const from = this.getPages().slice(-1)[0];
-			const to: RouteInfo = { path, meta: meta ?? {} };
-			(this._events["beforeEach"] as BeforeEach)(
-				to,
-				from,
-				next
-			);
-		} else {
-			next();
-		}
+	}
+
+	// 获取页面元数据
+	getMeta(path: string) {
+		return PAGES.find((e) => e.path.includes(path))?.meta ?? ({} as UTSJSONObject);
 	}
 
 	// 执行当前页面暴露的方法
@@ -296,21 +332,21 @@ export class Router {
 			});
 		}
 		// 登录后回调
-		if (isFunction(this._events["afterLogin"])) {
-			(this._events["afterLogin"] as AfterLogin)();
+		if (this.eventsMap.afterLogin != null) {
+			this.eventsMap.afterLogin!();
 		}
 		// 触发全局 afterLogin 事件
 		uni.$emit("afterLogin");
 	}
 
 	// 注册跳转前钩子
-	beforeEach(callback: BeforeEach) {
-		this._events["beforeEach"] = callback;
+	beforeEach(cb: BeforeEach) {
+		this.eventsMap.beforeEach = cb;
 	}
 
 	// 注册登录后回调
-	afterLogin(callback: AfterLogin) {
-		this._events["afterLogin"] = callback;
+	afterLogin(cb: AfterLogin) {
+		this.eventsMap.afterLogin = cb;
 	}
 }
 

+ 3 - 2
cool/types/index.ts

@@ -37,8 +37,9 @@ export type PushOptions = {
 	path: string;
 	mode?: PushMode;
 	events?: any;
-	query?: any;
-	params?: any;
+	query?: UTSJSONObject;
+	isAuth?: boolean;
+	params?: UTSJSONObject;
 	animationType?: PushAnimationType;
 	animationDuration?: number;
 	success?: (result: any) => void;

+ 2 - 4
manifest.json

@@ -1,13 +1,11 @@
 {
 	"name": "cool-unix",
-	"appid": "__UNI__EC807C1",
+	"appid": "__UNI__651711F",
 	"description": "完全开源、永久免费、上手容易、效率极高的开发脚手架",
 	"versionName": "1.0.0",
 	"versionCode": "100",
 	"uni-app-x": {},
-	/* 快应用特有相关 */
 	"quickapp": {},
-	/* 小程序特有相关 */
 	"mp-weixin": {
 		"darkmode": true,
 		"appid": "wxdebc4de0b5584ca4",
@@ -93,4 +91,4 @@
 			"splashScreens": {}
 		}
 	}
-}
+}

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 	"name": "cool-unix",
-	"version": "8.0.25",
+	"version": "8.0.26",
 	"license": "MIT",
 	"scripts": {
 		"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",

+ 20 - 8
pages.json

@@ -28,7 +28,7 @@
 					"style": {
 						"navigationBarTitleText": "设置"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -37,7 +37,7 @@
 					"style": {
 						"navigationBarTitleText": "通用设置"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -46,7 +46,7 @@
 					"style": {
 						"navigationBarTitleText": "通知设置"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -55,7 +55,7 @@
 					"style": {
 						"navigationBarTitleText": ""
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -64,7 +64,7 @@
 					"style": {
 						"navigationBarTitleText": "联系客服"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				}
@@ -78,7 +78,7 @@
 					"style": {
 						"navigationBarTitleText": "编辑资料"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -87,7 +87,7 @@
 					"style": {
 						"navigationStyle": "custom"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -96,7 +96,7 @@
 					"style": {
 						"navigationStyle": "custom"
 					},
-					"meta":{
+					"meta": {
 						"isAuth": true
 					}
 				},
@@ -489,6 +489,15 @@
 					"style": {
 						"navigationBarTitleText": "Animation 动画"
 					}
+				},
+				{
+					"path": "other/router/index",
+					"style": {
+						"navigationBarTitleText": "Router 路由"
+					}
+				},
+				{
+					"path": "other/router/query"
 				}
 			]
 		},
@@ -512,6 +521,9 @@
 					"style": {
 						"navigationBarTitleText": "收货地址",
 						"enablePullDownRefresh": true
+					},
+					"meta": {
+						"isAuth": true
 					}
 				},
 				{

+ 41 - 0
pages/demo/other/router/index.uvue

@@ -0,0 +1,41 @@
+<template>
+	<cl-page>
+		<view class="p-3">
+			<demo-item :label="t('跳转')">
+				<cl-button @click="toPush">{{ t("跳转") }}</cl-button>
+			</demo-item>
+
+			<demo-item :label="t('带参数')">
+				<cl-button @click="toQuery">{{ t("跳转") }}</cl-button>
+			</demo-item>
+
+			<demo-item :label="t('需登录')">
+				<cl-button @click="toLogin">{{ t("跳转") }}</cl-button>
+			</demo-item>
+		</view>
+	</cl-page>
+</template>
+
+<script lang="ts" setup>
+import { router, uuid } from "@/cool";
+import DemoItem from "../../components/item.uvue";
+import { t } from "@/locale";
+
+function toPush() {
+	router.to("/pages/demo/other/router/query");
+}
+
+function toQuery() {
+	router.push({ path: "/pages/demo/other/router/query", query: { id: uuid() } });
+}
+
+function toLogin() {
+	router.push({
+		path: "/pages/demo/other/router/query",
+		query: { id: uuid() },
+		isAuth: true
+	});
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 29 - 0
pages/demo/other/router/query.uvue

@@ -0,0 +1,29 @@
+<template>
+	<cl-page>
+		<view class="p-3">
+			<demo-item :label="t('ID')">
+				<cl-text>{{ id ?? "-" }}</cl-text>
+			</demo-item>
+
+			<demo-item :label="t('用户信息')" v-if="!user.isNull()">
+				<cl-text>{{ userInfo?.nickName ?? "-" }}</cl-text>
+			</demo-item>
+		</view>
+	</cl-page>
+</template>
+
+<script lang="ts" setup>
+import { t } from "@/locale";
+import DemoItem from "../../components/item.uvue";
+import { userInfo, useStore } from "@/cool";
+
+const { user } = useStore();
+
+const props = defineProps({
+	id: {
+		type: String
+	}
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 8 - 3
pages/index/home.uvue

@@ -46,9 +46,9 @@
 
 		<view class="p-3">
 			<view class="group" v-for="item in data" :key="item.label">
-				<cl-text :pt="{ className: '!text-sm !text-surface-400 mb-2 ml-2' }">{{
-					item.label
-				}}({{ item.children?.length ?? 0 }})</cl-text>
+				<cl-text :pt="{ className: '!text-sm !text-surface-400 mb-2 ml-2' }"
+					>{{ item.label }}({{ item.children?.length ?? 0 }})</cl-text
+				>
 
 				<view class="list">
 					<cl-row :gutter="10">
@@ -461,6 +461,11 @@ const data = computed<Item[]>(() => {
 					label: "Animation",
 					icon: "instance-line",
 					path: "/pages/demo/other/animation"
+				},
+				{
+					label: "Router",
+					icon: "compass-discover-line",
+					path: "/pages/demo/other/router/index"
 				}
 			]
 		}

+ 12 - 3
router/index.ts

@@ -1,8 +1,17 @@
 import { router, useStore } from "@/cool";
 
-router.beforeEach((to, _, next) => {
+/**
+ * 路由跳转前的全局钩子(如修改 pages.json 后需重新编译项目以确保路由信息生效)
+ * @param to 跳转页
+ * @param from 当前页
+ * @param next 跳转函数
+ */
+router.beforeEach((to, from, next) => {
 	const { user } = useStore();
-	if (to.meta?.isAuth == true) {
+
+	// 判断是否需要登录
+	if (to.isAuth == true || to.meta?.isAuth == true) {
+		// 如果用户信息为空,则跳转到登录页
 		if (!user.isNull()) {
 			next();
 		} else {
@@ -11,4 +20,4 @@ router.beforeEach((to, _, next) => {
 	} else {
 		next();
 	}
-});
+});