智能小程序 Ray 开发路由 API 合集

一、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 长度有限制,对象参数不宜过大
  • 对象参数需使用 encodeURIComponentdecodeURIComponent进行编码解码
  • 参数会在页面 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 智能小程序开发框架提供了完善的路由管理方案,通过合理的路由配置、跳转方法封装、权限控制和性能优化,可以构建出高效、稳定的小程序应用。开发者应结合业务需求,选择合适的路由策略,提升用户体验和应用性能。

版权声明:本文为JienDa博主的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
若内容若侵犯到您的权益,请发送邮件至:platform_service@jienda.com我们将第一时间处理!
所有资源仅限于参考和学习,版权归JienDa作者所有,更多请访问JienDa首页。

给TA赞助
共{{data.count}}人
人已赞助
后端

二手交易系统基于Uniapp+FastAdmin+ThinkPHP

2025-12-19 23:06:39

后端

酒店预订系统开发方案详解

2025-12-19 23:13:54

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索