优化 router,支持 isAuth,并添加示例
This commit is contained in:
@@ -64,7 +64,7 @@ if (isArray(ctx.subPackages)) {
|
|||||||
PAGES.push({
|
PAGES.push({
|
||||||
path: a.root + "/" + b.path, // 拼接子包根路径和页面路径
|
path: a.root + "/" + b.path, // 拼接子包根路径和页面路径
|
||||||
style: b.style,
|
style: b.style,
|
||||||
meta: b.meta ?? {},
|
meta: b.meta
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
import { PAGES, TABS } from "../ctx";
|
import { PAGES, TABS } from "../ctx";
|
||||||
import type { BackOptions, PageInstance, PushOptions } from "../types";
|
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 = {
|
type RouteInfo = {
|
||||||
path: string;
|
path: string;
|
||||||
meta?: UTSJSONObject;
|
query: UTSJSONObject;
|
||||||
|
meta: UTSJSONObject;
|
||||||
|
isAuth?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 跳转前钩子类型
|
// 跳转前钩子类型
|
||||||
@@ -21,15 +34,11 @@ type Events = {
|
|||||||
|
|
||||||
// 路由核心类
|
// 路由核心类
|
||||||
export class Router {
|
export class Router {
|
||||||
private _events = {} as Events; // 事件存储
|
private eventsMap = {} as Events; // 事件存储
|
||||||
|
|
||||||
// 获取缓存的路由参数
|
// 获取缓存的路由参数
|
||||||
params() {
|
params() {
|
||||||
const data = storage.get("router-params") as UTSJSONObject;
|
return (storage.get("router-params") ?? {}) as UTSJSONObject;
|
||||||
if (isNull(data)) {
|
|
||||||
return {} as UTSJSONObject;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取默认路径,支持 home 和 login
|
// 获取默认路径,支持 home 和 login
|
||||||
@@ -38,6 +47,7 @@ export class Router {
|
|||||||
home: PAGES[0].path, // 首页为第一个页面
|
home: PAGES[0].path, // 首页为第一个页面
|
||||||
login: "/pages/user/login"
|
login: "/pages/user/login"
|
||||||
};
|
};
|
||||||
|
|
||||||
return get(paths, name) as string;
|
return get(paths, name) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,31 +55,38 @@ export class Router {
|
|||||||
getPages(): PageInstance[] {
|
getPages(): PageInstance[] {
|
||||||
return map(getCurrentPages(), (e) => {
|
return map(getCurrentPages(), (e) => {
|
||||||
let path = e.route!;
|
let path = e.route!;
|
||||||
|
|
||||||
// 根路径自动转为首页
|
// 根路径自动转为首页
|
||||||
if (path == "/") {
|
if (path == "/") {
|
||||||
path = this.defaultPath("home");
|
path = this.defaultPath("home");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 补全路径前缀
|
// 补全路径前缀
|
||||||
if (!path.startsWith("/")) {
|
if (!path.startsWith("/")) {
|
||||||
path = "/" + path;
|
path = "/" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取页面样式
|
// 获取页面样式
|
||||||
const page = PAGES.find((e) => e.path == path);
|
const page = PAGES.find((e) => e.path == path);
|
||||||
const style = page?.style;
|
const style = page?.style;
|
||||||
const meta = page?.meta;
|
const meta = page?.meta;
|
||||||
|
|
||||||
// 获取页面暴露的方法
|
// 获取页面暴露的方法
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let exposed = e.vm as any;
|
const vm = e.vm as any;
|
||||||
|
|
||||||
|
let exposed = vm;
|
||||||
|
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
exposed = get(e, "vm.$.exposed");
|
exposed = get(e, "vm.$.exposed");
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// 获取页面 query 参数
|
// 获取页面 query 参数
|
||||||
const query = (get(e, "options") ?? {}) as UTSJSONObject;
|
const query = (get(e, "options") ?? {}) as UTSJSONObject;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path,
|
path,
|
||||||
// @ts-ignore
|
vm,
|
||||||
vm: e.vm!,
|
|
||||||
// @ts-ignore
|
|
||||||
exposed,
|
exposed,
|
||||||
style,
|
style,
|
||||||
meta,
|
meta,
|
||||||
@@ -113,7 +130,8 @@ export class Router {
|
|||||||
complete,
|
complete,
|
||||||
animationType,
|
animationType,
|
||||||
animationDuration,
|
animationDuration,
|
||||||
events
|
events,
|
||||||
|
isAuth
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
// 拼接 query 参数到 url
|
// 拼接 query 参数到 url
|
||||||
@@ -176,15 +194,15 @@ export class Router {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 跳转前钩子处理
|
// 跳转前钩子处理
|
||||||
if (isFunction(this._events["beforeEach"])) {
|
if (this.eventsMap.beforeEach != null) {
|
||||||
const meta = PAGES.find((e) => e.path == path)?.meta;
|
// 当前页
|
||||||
const from = this.getPages().slice(-1)[0];
|
const from = last(this.getPages());
|
||||||
const to: RouteInfo = { path, meta: meta ?? {} };
|
|
||||||
(this._events["beforeEach"] as BeforeEach)(
|
// 跳转页
|
||||||
to,
|
const to = { path, meta: this.getMeta(path), query, isAuth } as RouteInfo;
|
||||||
from,
|
|
||||||
next
|
// 调用跳转前钩子
|
||||||
);
|
this.eventsMap.beforeEach(to, from!, next);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
@@ -197,31 +215,49 @@ export class Router {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回上一页,若为首页则回首页
|
// 返回上一页
|
||||||
back(options: BackOptions | null = null) {
|
back(options: BackOptions | null = null) {
|
||||||
let path = ''
|
if (this.isFirstPage()) {
|
||||||
const next = ()=>{
|
this.home();
|
||||||
if (this.isFirstPage()) {
|
} else {
|
||||||
this.home();
|
const delta = options?.delta ?? 1;
|
||||||
path = this.defaultPath("home")
|
|
||||||
} else {
|
// 执行跳转函数
|
||||||
path = this.getPages().slice(-2)[0].path;
|
const next = () => {
|
||||||
uni.navigateBack({ ...(options ?? {}) });
|
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];
|
getMeta(path: string) {
|
||||||
const to: RouteInfo = { path, meta: meta ?? {} };
|
return PAGES.find((e) => e.path.includes(path))?.meta ?? ({} as UTSJSONObject);
|
||||||
(this._events["beforeEach"] as BeforeEach)(
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
next
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行当前页面暴露的方法
|
// 执行当前页面暴露的方法
|
||||||
@@ -296,21 +332,21 @@ export class Router {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 登录后回调
|
// 登录后回调
|
||||||
if (isFunction(this._events["afterLogin"])) {
|
if (this.eventsMap.afterLogin != null) {
|
||||||
(this._events["afterLogin"] as AfterLogin)();
|
this.eventsMap.afterLogin!();
|
||||||
}
|
}
|
||||||
// 触发全局 afterLogin 事件
|
// 触发全局 afterLogin 事件
|
||||||
uni.$emit("afterLogin");
|
uni.$emit("afterLogin");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册跳转前钩子
|
// 注册跳转前钩子
|
||||||
beforeEach(callback: BeforeEach) {
|
beforeEach(cb: BeforeEach) {
|
||||||
this._events["beforeEach"] = callback;
|
this.eventsMap.beforeEach = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册登录后回调
|
// 注册登录后回调
|
||||||
afterLogin(callback: AfterLogin) {
|
afterLogin(cb: AfterLogin) {
|
||||||
this._events["afterLogin"] = callback;
|
this.eventsMap.afterLogin = cb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ export type PushOptions = {
|
|||||||
path: string;
|
path: string;
|
||||||
mode?: PushMode;
|
mode?: PushMode;
|
||||||
events?: any;
|
events?: any;
|
||||||
query?: any;
|
query?: UTSJSONObject;
|
||||||
params?: any;
|
isAuth?: boolean;
|
||||||
|
params?: UTSJSONObject;
|
||||||
animationType?: PushAnimationType;
|
animationType?: PushAnimationType;
|
||||||
animationDuration?: number;
|
animationDuration?: number;
|
||||||
success?: (result: any) => void;
|
success?: (result: any) => void;
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "cool-unix",
|
"name": "cool-unix",
|
||||||
"appid": "__UNI__EC807C1",
|
"appid": "__UNI__651711F",
|
||||||
"description": "完全开源、永久免费、上手容易、效率极高的开发脚手架",
|
"description": "完全开源、永久免费、上手容易、效率极高的开发脚手架",
|
||||||
"versionName": "1.0.0",
|
"versionName": "1.0.0",
|
||||||
"versionCode": "100",
|
"versionCode": "100",
|
||||||
"uni-app-x": {},
|
"uni-app-x": {},
|
||||||
/* 快应用特有相关 */
|
|
||||||
"quickapp": {},
|
"quickapp": {},
|
||||||
/* 小程序特有相关 */
|
|
||||||
"mp-weixin": {
|
"mp-weixin": {
|
||||||
"darkmode": true,
|
"darkmode": true,
|
||||||
"appid": "wxdebc4de0b5584ca4",
|
"appid": "wxdebc4de0b5584ca4",
|
||||||
@@ -93,4 +91,4 @@
|
|||||||
"splashScreens": {}
|
"splashScreens": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cool-unix",
|
"name": "cool-unix",
|
||||||
"version": "8.0.25",
|
"version": "8.0.26",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",
|
"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",
|
||||||
|
|||||||
28
pages.json
28
pages.json
@@ -28,7 +28,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "设置"
|
"navigationBarTitleText": "设置"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "通用设置"
|
"navigationBarTitleText": "通用设置"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "通知设置"
|
"navigationBarTitleText": "通知设置"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": ""
|
"navigationBarTitleText": ""
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "联系客服"
|
"navigationBarTitleText": "联系客服"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "编辑资料"
|
"navigationBarTitleText": "编辑资料"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
},
|
},
|
||||||
"meta":{
|
"meta": {
|
||||||
"isAuth": true
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -489,6 +489,15 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "Animation 动画"
|
"navigationBarTitleText": "Animation 动画"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "other/router/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "Router 路由"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "other/router/query"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -512,6 +521,9 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "收货地址",
|
"navigationBarTitleText": "收货地址",
|
||||||
"enablePullDownRefresh": true
|
"enablePullDownRefresh": true
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"isAuth": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
41
pages/demo/other/router/index.uvue
Normal file
41
pages/demo/other/router/index.uvue
Normal file
@@ -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
pages/demo/other/router/query.uvue
Normal file
29
pages/demo/other/router/query.uvue
Normal file
@@ -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>
|
||||||
@@ -46,9 +46,9 @@
|
|||||||
|
|
||||||
<view class="p-3">
|
<view class="p-3">
|
||||||
<view class="group" v-for="item in data" :key="item.label">
|
<view class="group" v-for="item in data" :key="item.label">
|
||||||
<cl-text :pt="{ className: '!text-sm !text-surface-400 mb-2 ml-2' }">{{
|
<cl-text :pt="{ className: '!text-sm !text-surface-400 mb-2 ml-2' }"
|
||||||
item.label
|
>{{ item.label }}({{ item.children?.length ?? 0 }})</cl-text
|
||||||
}}({{ item.children?.length ?? 0 }})</cl-text>
|
>
|
||||||
|
|
||||||
<view class="list">
|
<view class="list">
|
||||||
<cl-row :gutter="10">
|
<cl-row :gutter="10">
|
||||||
@@ -461,6 +461,11 @@ const data = computed<Item[]>(() => {
|
|||||||
label: "Animation",
|
label: "Animation",
|
||||||
icon: "instance-line",
|
icon: "instance-line",
|
||||||
path: "/pages/demo/other/animation"
|
path: "/pages/demo/other/animation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Router",
|
||||||
|
icon: "compass-discover-line",
|
||||||
|
path: "/pages/demo/other/router/index"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
import { router, useStore } from "@/cool";
|
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();
|
const { user } = useStore();
|
||||||
if (to.meta?.isAuth == true) {
|
|
||||||
|
// 判断是否需要登录
|
||||||
|
if (to.isAuth == true || to.meta?.isAuth == true) {
|
||||||
|
// 如果用户信息为空,则跳转到登录页
|
||||||
if (!user.isNull()) {
|
if (!user.isNull()) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
@@ -11,4 +20,4 @@ router.beforeEach((to, _, next) => {
|
|||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user