一、Ray 框架路由配置基础
Ray 开发框架采用基于 TypeScript 的现代化路由配置方案,通过 src/routes.config.ts文件统一管理应用路由。该配置文件采用标准的 JSON 格式,支持路由路径表达式和 TabBar 配置。
1.1 路由配置文件结构
import { Routes, TabBar } from '@ray-js/types';
export const routes: Routes = [
{
id: 'home',
route: '/home',
path: '/pages/home/index'
},
{
id: 'detail',
route: '/detail/:id',
path: '/pages/detail/index'
}
];
export const tabBar: TabBar = {
textColor: '#999999',
selectedColor: '#007AFF',
backgroundColor: '#FFFFFF',
list: [
{
text: '首页',
icon: '/assets/tabbar/home.png',
activeIcon: '/assets/tabbar/home-active.png',
id: 'home',
route: '/home'
}
]
};
1.2 路由对象属性详解
| 属性名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | 否 | 路由唯一标识符,用于TabBar关联 |
| route | string | 是 | 路由路径表达式,支持动态参数 |
| path | string | 是 | 页面组件物理路径 |
注意事项:
- 路由匹配采用后覆盖前的优先级顺序,开发者需自行保证路由优先级关系
- route 表达式应符合 path-to-regexp 规范,支持动态参数(如
/:id) - TabBar 的 icon 和 activeIcon 仅支持本地图片,且需使用绝对路径
二、路由跳转 API
Ray 框架提供了丰富的路由跳转方法,支持多种跳转场景和参数传递方式。
2.1 基础跳转方法
2.1.1 navigateTo – 保留当前页面跳转
import { navigateTo } from '@ray-js/ray';
// 普通跳转
navigateTo({
url: '/pages/detail/index?id=123&name=test'
});
// 带回调的跳转
navigateTo({
url: '/pages/detail/index',
success: (res) => {
console.log('跳转成功', res);
},
fail: (err) => {
console.error('跳转失败', err);
},
complete: () => {
console.log('跳转完成');
}
});
特点:
- 保留当前页面,新页面压入页面栈
- 最多支持10层页面嵌套
- 不能跳转到 tabBar 页面
2.1.2 redirectTo – 关闭当前页面跳转
import { redirectTo } from '@ray-js/ray';
redirectTo({
url: '/pages/home/index'
});
特点:
- 关闭当前页面,新页面替换当前页面
- 适用于登录后跳转等场景
- 不能跳转到 tabBar 页面
2.1.3 switchTab – 跳转到 TabBar 页面
import { switchTab } from '@ray-js/ray';
switchTab({
url: '/pages/index/index'
});
特点:
- 跳转到 tabBar 页面并关闭当前页面
- 路径后不能带参数
- 会关闭所有非 tabBar 页面
2.1.4 reLaunch – 重启应用
import { reLaunch } from '@ray-js/ray';
reLaunch({
url: '/pages/index/index'
});
特点:
- 关闭所有页面,打开到应用内的某个页面
- 适用于应用重启或退出登录后跳转
- 支持跳转到任意页面
2.1.5 navigateBack – 返回上一页
import { navigateBack } from '@ray-js/ray';
// 返回上一页
navigateBack();
// 返回多级页面
navigateBack({
delta: 2
});
特点:
- 关闭当前页面,返回上一页面或多级页面
- delta 参数指定返回的页面层数,默认为1
2.2 路由跳转封装实践
在实际开发中,建议对路由跳转进行统一封装,便于维护和权限控制:
// utils/router.ts
import { navigateTo, redirectTo, switchTab, reLaunch, navigateBack } from '@ray-js/ray';
class Router {
// 判断是否为TabBar页面
private static isTabBarPage(url: string): boolean {
const tabBarPages = ['/pages/index/index', '/pages/user/index'];
return tabBarPages.includes(url);
}
// 统一跳转方法
static jump(url: string, type: 'navigateTo' | 'redirectTo' | 'reLaunch' = 'navigateTo') {
if (this.isTabBarPage(url)) {
switchTab({ url });
return;
}
switch (type) {
case 'navigateTo':
navigateTo({ url });
break;
case 'redirectTo':
redirectTo({ url });
break;
case 'reLaunch':
reLaunch({ url });
break;
}
}
// 返回方法
static back(delta: number = 1) {
navigateBack({ delta });
}
}
export default Router;
使用方式:
import Router from '@/utils/router';
// 普通跳转
Router.jump('/pages/detail/index');
// 重定向跳转
Router.jump('/pages/login/index', 'redirectTo');
// 返回上一页
Router.back();
三、路由传参机制
Ray 框架支持多种路由传参方式,满足不同业务场景需求。
3.1 Query 参数传递
3.1.1 传递参数
// 传递简单参数
navigateTo({
url: '/pages/detail/index?id=123&name=张三'
});
// 传递对象参数(需转为JSON字符串)
const data = { id: 123, name: '张三', age: 25 };
const params = encodeURIComponent(JSON.stringify(data));
navigateTo({
url: `/pages/detail/index?data=${params}`
});
3.1.2 接收参数
// pages/detail/index.tsx
import { usePageEvent } from '@ray-js/ray';
export default function Detail() {
usePageEvent('onLoad', (options) => {
console.log('页面参数', options);
// 输出: { id: '123', name: '张三' }
// 解析对象参数
if (options.data) {
const data = JSON.parse(decodeURIComponent(options.data));
console.log('对象参数', data);
}
});
return <view>详情页面</view>;
}
注意事项:
- URL 长度有限制,对象参数不宜过大
- 对象参数需使用
encodeURIComponent和decodeURIComponent进行编码解码 - 参数会在页面
onLoad生命周期中通过options参数获取
3.2 EventChannel 事件通道传参
EventChannel 提供了更灵活的数据传递方式,支持复杂对象和双向通信。
3.2.1 发送端
navigateTo({
url: '/pages/detail/index',
success: (res) => {
// 通过事件通道传递数据
res.eventChannel.emit('acceptDataFromOpenerPage', {
id: 123,
name: '张三',
data: { age: 25, city: '北京' }
});
}
});
3.2.2 接收端
// pages/detail/index.tsx
import { usePageEvent } from '@ray-js/ray';
export default function Detail() {
usePageEvent('onLoad', (options) => {
const eventChannel = this.getOpenerEventChannel();
eventChannel.on('acceptDataFromOpenerPage', (data) => {
console.log('接收到的数据', data);
// 输出: { id: 123, name: '张三', data: { age: 25, city: '北京' } }
});
});
return <view>详情页面</view>;
}
特点:
- 支持传递复杂对象,无需担心URL长度限制
- 支持双向通信,子页面可以向父页面发送数据
- 需要在
onLoad生命周期中获取 EventChannel
3.3 全局变量传参
对于需要在多个页面间共享的数据,可以使用全局变量:
// app.ts
import { createApp } from '@ray-js/ray';
const app = createApp({
globalData: {
userInfo: null,
token: ''
}
});
export default app;
// 页面中设置全局变量
getApp().globalData.userInfo = { id: 123, name: '张三' };
// 页面中获取全局变量
const userInfo = getApp().globalData.userInfo;
适用场景:
- 用户登录信息、Token等全局状态
- 需要在多个页面间共享的数据
- 避免频繁通过路由传递相同参数
四、路由拦截与权限控制
Ray 框架虽然未提供内置的路由守卫,但可以通过封装路由方法和页面生命周期实现权限控制。
4.1 路由方法封装拦截
4.1.1 封装路由跳转方法
// utils/router-guard.ts
import { navigateTo, redirectTo, switchTab, reLaunch } from '@ray-js/ray';
class RouterGuard {
// 检查登录状态
private static checkLogin(): boolean {
const token = getApp().globalData.token;
return !!token;
}
// 检查权限
private static checkPermission(permission: string): boolean {
const userPermissions = getApp().globalData.userPermissions || [];
return userPermissions.includes(permission);
}
// 封装 navigateTo
static navigateTo(options: {
url: string;
requiresAuth?: boolean;
permission?: string;
success?: Function;
fail?: Function;
complete?: Function;
}) {
const { requiresAuth = false, permission, ...rest } = options;
// 登录检查
if (requiresAuth && !this.checkLogin()) {
this.showLoginToast();
return;
}
// 权限检查
if (permission && !this.checkPermission(permission)) {
this.showPermissionToast();
return;
}
navigateTo(rest);
}
// 封装 redirectTo
static redirectTo(options: {
url: string;
requiresAuth?: boolean;
permission?: string;
success?: Function;
fail?: Function;
complete?: Function;
}) {
const { requiresAuth = false, permission, ...rest } = options;
if (requiresAuth && !this.checkLogin()) {
this.showLoginToast();
return;
}
if (permission && !this.checkPermission(permission)) {
this.showPermissionToast();
return;
}
redirectTo(rest);
}
// 提示方法
private static showLoginToast() {
// 显示登录提示
// 跳转到登录页
redirectTo({ url: '/pages/login/index' });
}
private static showPermissionToast() {
// 显示权限不足提示
}
}
export default RouterGuard;
4.1.2 使用方式
import RouterGuard from '@/utils/router-guard';
// 需要登录的页面
RouterGuard.navigateTo({
url: '/pages/profile/index',
requiresAuth: true
});
// 需要权限的页面
RouterGuard.navigateTo({
url: '/pages/admin/index',
requiresAuth: true,
permission: 'admin'
});
4.2 页面生命周期拦截
在页面组件的生命周期中实现权限检查:
// pages/profile/index.tsx
import { usePageEvent } from '@ray-js/ray';
export default function Profile() {
usePageEvent('onLoad', (options) => {
// 检查登录状态
if (!getApp().globalData.token) {
redirectTo({ url: '/pages/login/index' });
return;
}
});
usePageEvent('onShow', () => {
// 页面显示时检查权限
if (!this.checkPermission()) {
navigateBack();
return;
}
});
return <view>个人中心</view>;
}
4.3 全局路由守卫实现
通过全局 App 对象实现类似 Vue Router 的 beforeEach 守卫:
// app.ts
import { createApp } from '@ray-js/ray';
const app = createApp({
// 路由守卫对象
routerGuard: {
// 全局前置守卫
beforeEach(to: string, from: string, next: Function) {
console.log('路由跳转前', from, '->', to);
// 检查登录状态
if (to.includes('/pages/profile') && !getApp().globalData.token) {
redirectTo({ url: '/pages/login/index' });
return;
}
next();
},
// 全局后置钩子
afterEach(to: string, from: string) {
console.log('路由跳转后', from, '->', to);
}
}
});
export default app;
// 在页面中使用
// pages/detail/index.tsx
import { usePageEvent } from '@ray-js/ray';
export default function Detail() {
usePageEvent('onLoad', (options) => {
getApp().routerGuard.beforeEach('/pages/detail/index', '/pages/home/index', () => {
// 守卫通过后的逻辑
});
});
usePageEvent('onUnload', () => {
getApp().routerGuard.afterEach('/pages/detail/index', '/pages/home/index');
});
return <view>详情页面</view>;
}
最佳实践建议:
- 对于简单的权限检查,推荐使用路由方法封装
- 对于复杂项目,推荐组合使用全局守卫和页面生命周期检查
- 将权限检查逻辑集中管理,便于维护
五、路由模式与配置
5.1 路由模式配置
Ray 框架支持多种路由模式,通过配置文件进行设置:
// src/routes.config.ts
import { Routes, TabBar, RouterConfig } from '@ray-js/types';
export const routerConfig: RouterConfig = {
// 路由模式,默认为 'hash'
mode: 'history',
// 基础路径,默认为 '/'
base: '/app',
// 是否启用路由懒加载,默认为 true
lazy: true,
// 路由动画配置
animation: {
duration: 300,
timingFunction: 'ease-in-out'
}
};
export const routes: Routes = [
// 路由配置
];
export const tabBar: TabBar = {
// TabBar配置
};
5.2 动态路由配置
支持动态生成路由配置,适用于权限动态加载的场景:
// src/routes.config.ts
import { Routes } from '@ray-js/types';
// 获取动态路由配置
const getDynamicRoutes = async (): Promise<Routes> => {
try {
const response = await fetch('/api/routes');
const routes = await response.json();
return routes;
} catch (error) {
return [];
}
};
// 动态路由配置
export const routes: Routes = [
// 静态路由
{
id: 'home',
route: '/home',
path: '/pages/home/index'
},
// 动态路由
...(await getDynamicRoutes())
];
5.3 路由优先级配置
路由匹配采用后覆盖前的优先级顺序,开发者需要合理配置路由顺序:
export const routes: Routes = [
// 通用路由(低优先级)
{
id: 'detail',
route: '/detail/:id',
path: '/pages/detail/index'
},
// 特定路由(高优先级)
{
id: 'detail-special',
route: '/detail/special',
path: '/pages/detail/special'
},
// 404页面(最低优先级)
{
id: 'not-found',
route: '*',
path: '/pages/not-found/index'
}
];
六、路由懒加载与性能优化
6.1 路由懒加载配置
Ray 框架默认支持路由懒加载,通过动态导入实现按需加载:
// src/routes.config.ts
export const routes: Routes = [
{
id: 'detail',
route: '/detail/:id',
path: () => import('/pages/detail/index')
}
];
懒加载的优势:
- 减少初始加载时间,提升首屏加载速度
- 按需加载资源,提升资源利用率
- 减少内存占用,提升应用性能
6.2 预加载策略
对于重要页面,可以使用预加载机制提前加载资源:
// utils/preload.ts
import { getCurrentPages } from '@ray-js/ray';
class PreloadManager {
// 预加载页面
static preloadPage(path: string) {
// 动态导入页面组件
import(path).then(module => {
console.log('页面预加载完成', path);
}).catch(error => {
console.error('页面预加载失败', error);
});
}
// 根据当前页面预加载相关页面
static preloadRelatedPages() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
switch (currentPage.route) {
case '/pages/home/index':
this.preloadPage('/pages/detail/index');
this.preloadPage('/pages/profile/index');
break;
case '/pages/list/index':
this.preloadPage('/pages/detail/index');
break;
}
}
}
export default PreloadManager;
6.3 数据缓存优化
通过缓存机制减少重复网络请求:
// utils/cache.ts
class CacheManager {
// 设置缓存
static setCache(key: string, data: any, expire: number = 300000) {
const cacheData = {
data,
expire: Date.now() + expire
};
wx.setStorageSync(key, cacheData);
}
// 获取缓存
static getCache(key: string): any {
const cacheData = wx.getStorageSync(key);
if (!cacheData || cacheData.expire < Date.now()) {
return null;
}
return cacheData.data;
}
// 清除缓存
static clearCache(key: string) {
wx.removeStorageSync(key);
}
}
export default CacheManager;
// 页面中使用
import CacheManager from '@/utils/cache';
// 设置缓存
CacheManager.setCache('userInfo', userData, 3600000);
// 获取缓存
const userInfo = CacheManager.getCache('userInfo');
if (userInfo) {
// 使用缓存数据
} else {
// 请求网络数据
}
6.4 页面栈深度优化
合理使用跳转方法,避免页面栈过深:
// 推荐使用 redirectTo 或 reLaunch 替代 navigateTo
// 在页面流程结束后,清理页面栈
redirectTo({ url: '/pages/home/index' });
// 或者
reLaunch({ url: '/pages/home/index' });
// 避免使用 navigateTo 导致页面栈过深
// navigateTo({ url: '/pages/detail/index' }); // 不推荐
优化建议:
- 页面栈最多支持10层,需定期检查页面栈深度
- 在合适的时机使用 redirectTo 或 reLaunch 清理页面栈
- 避免在循环或频繁操作中使用 navigateTo
七、路由动画与转场效果
7.1 自定义路由动画
Ray 框架支持自定义页面转场动画,提供类原生动画体验:
// utils/route-animation.ts
import { router } from '@ray-js/ray';
// 定义路由动画构建器
const customRouteBuilder = (route: any) => {
const { primaryAnimation, secondaryAnimation } = route;
// 主页面动画(新页面)
const handlePrimaryAnimation = () => {
// 从底部滑入
return {
transform: [
{
translateY: primaryAnimation.interpolate({
inputRange: [0, 1],
outputRange: [100, 0]
})
}
],
opacity: primaryAnimation
};
};
// 次页面动画(旧页面)
const handleSecondaryAnimation = () => {
// 淡出
return {
opacity: secondaryAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1, 0]
})
};
};
return {
handlePrimaryAnimation,
handleSecondaryAnimation
};
};
// 注册自定义路由
router.addRouteBuilder('custom', customRouteBuilder);
export default customRouteBuilder;
7.2 使用自定义动画
import { navigateTo } from '@ray-js/ray';
// 使用自定义动画跳转
navigateTo({
url: '/pages/detail/index',
routeType: 'custom' // 指定路由类型
});
7.3 动画曲线配置
支持多种动画缓动函数,提供丰富的动画效果:
// 动画曲线函数
const easingFunctions = {
// 线性
linear: (t: number) => t,
// 缓入
easeIn: (t: number) => t * t,
// 缓出
easeOut: (t: number) => t * (2 - t),
// 缓入缓出
easeInOut: (t: number) => {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
},
// 弹性
elastic: (t: number) => {
return Math.sin(-13 * (t + 1) * Math.PI / 2) * Math.pow(2, -10 * t) + 1;
}
};
// 在动画构建器中使用
const handlePrimaryAnimation = () => {
const animatedValue = primaryAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
easing: easingFunctions.easeInOut
});
return {
transform: [
{
translateY: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [100, 0]
})
}
]
};
};
动画效果类型:
- 平移动画(translateX、translateY)
- 缩放动画(scale)
- 旋转动画(rotate)
- 透明度动画(opacity)
- 组合动画
八、路由错误处理与404页面
8.1 404页面配置
在路由配置中定义404页面:
// src/routes.config.ts
export const routes: Routes = [
// 其他路由...
{
id: 'not-found',
route: '*',
path: '/pages/not-found/index'
}
];
8.2 全局错误处理
在 App 中配置全局错误处理:
// app.ts
import { createApp } from '@ray-js/ray';
const app = createApp({
onError(error: any) {
console.error('全局错误', error);
// 可以跳转到错误页面或显示错误提示
},
onPageNotFound(res: any) {
console.log('页面不存在', res);
// 跳转到404页面
redirectTo({ url: '/pages/not-found/index' });
}
});
export default app;
8.3 网络请求错误处理
封装网络请求方法,统一处理错误:
// utils/request.ts
import { request } from '@ray-js/ray';
class Request {
static async get(url: string, data?: any) {
try {
const response = await request({
url,
data,
method: 'GET'
});
if (response.statusCode === 404) {
// 跳转到404页面
redirectTo({ url: '/pages/not-found/index' });
return null;
}
return response.data;
} catch (error) {
console.error('请求失败', error);
// 显示错误提示
return null;
}
}
}
export default Request;
8.4 页面加载失败处理
在页面组件中处理加载失败情况:
// pages/detail/index.tsx
import { usePageEvent } from '@ray-js/ray';
export default function Detail() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
usePageEvent('onLoad', async (options) => {
try {
const data = await fetchDetailData(options.id);
setLoading(false);
} catch (error) {
setError(true);
setLoading(false);
}
});
if (loading) {
return <view>加载中...</view>;
}
if (error) {
return (
<view>
<text>页面加载失败</text>
<button onClick={() => navigateBack()}>返回</button>
</view>
);
}
return <view>详情页面</view>;
}
九、路由最佳实践
9.1 路由命名规范
// 路由命名规范
export const routes: Routes = [
{
id: 'home', // 使用小写字母和连字符
route: '/home',
path: '/pages/home/index'
},
{
id: 'product-detail', // 使用连字符分隔
route: '/product/:id',
path: '/pages/product/detail/index'
}
];
9.2 路由参数校验
// utils/validator.ts
class Validator {
// 校验路由参数
static validateRouteParams(params: any, rules: any): boolean {
for (const key in rules) {
if (!params[key]) {
console.error(`缺少必要参数: ${key}`);
return false;
}
if (rules[key] === 'number' && isNaN(Number(params[key]))) {
console.error(`参数类型错误: ${key} 应为数字`);
return false;
}
}
return true;
}
}
export default Validator;
// 页面中使用
usePageEvent('onLoad', (options) => {
const rules = {
id: 'number',
name: 'string'
};
if (!Validator.validateRouteParams(options, rules)) {
navigateBack();
return;
}
});
9.3 路由状态管理
// utils/route-state.ts
class RouteState {
// 保存页面状态
static saveState(key: string, state: any) {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const routeKey = `${currentPage.route}-${key}`;
wx.setStorageSync(routeKey, state);
}
// 恢复页面状态
static restoreState(key: string): any {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const routeKey = `${currentPage.route}-${key}`;
return wx.getStorageSync(routeKey);
}
// 清除页面状态
static clearState(key: string) {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const routeKey = `${currentPage.route}-${key}`;
wx.removeStorageSync(routeKey);
}
}
export default RouteState;
9.4 路由性能监控
// utils/performance.ts
class PerformanceMonitor {
// 记录路由跳转时间
static recordRouteNavigation(from: string, to: string) {
const startTime = Date.now();
return {
end: () => {
const endTime = Date.now();
const duration = endTime - startTime;
console.log(`路由跳转: ${from} -> ${to}, 耗时: ${duration}ms`);
// 上报性能数据
this.reportPerformance({
type: 'route_navigation',
from,
to,
duration
});
}
};
}
// 上报性能数据
private static reportPerformance(data: any) {
// 上报到监控平台
}
}
export default PerformanceMonitor;
// 在路由守卫中使用
const navigation = PerformanceMonitor.recordRouteNavigation(from, to);
// 路由跳转逻辑...
navigation.end();
十、总结
Ray 智能小程序开发框架提供了完善的路由管理方案,通过合理的路由配置、跳转方法封装、权限控制和性能优化,可以构建出高效、稳定的小程序应用。开发者应结合业务需求,选择合适的路由策略,提升用户体验和应用性能。
若内容若侵犯到您的权益,请发送邮件至:platform_service@jienda.com我们将第一时间处理!
所有资源仅限于参考和学习,版权归JienDa作者所有,更多请访问JienDa首页。





