阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 导航与路由(navigateTo、tabBar 等)

导航与路由(navigateTo、tabBar 等)

作者:陈川 阅读数:29901人阅读 分类: uni-app

路由跳转的基本方法

uni-app提供了多种路由跳转方式,最基础的是uni.navigateTo方法。这个方法会保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。

// 跳转到指定页面
uni.navigateTo({
  url: '/pages/detail/detail?id=1'
});

// 接收参数的页面
onLoad(options) {
  console.log(options.id); // 输出1
}

路由跳转时可以传递参数,参数会自动拼接到url后面。目标页面在onLoad生命周期中通过options参数获取这些值。

特殊路由跳转方式

除了常规跳转外,uni-app还提供了几种特殊的路由方法:

  1. uni.redirectTo - 关闭当前页面,跳转到应用内的某个页面
uni.redirectTo({
  url: '/pages/login/login'
});
  1. uni.reLaunch - 关闭所有页面,打开到应用内的某个页面
uni.reLaunch({
  url: '/pages/index/index'
});
  1. uni.switchTab - 跳转到tabBar页面,并关闭其他所有非tabBar页面
uni.switchTab({
  url: '/pages/home/home'
});

tabBar配置与使用

tabBar是uni-app中实现底部导航栏的功能。需要在pages.json中进行配置:

{
  "tabBar": {
    "color": "#999",
    "selectedColor": "#007AFF",
    "backgroundColor": "#ffffff",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/home/home",
        "text": "首页",
        "iconPath": "static/tab-home.png",
        "selectedIconPath": "static/tab-home-active.png"
      },
      {
        "pagePath": "pages/user/user",
        "text": "我的",
        "iconPath": "static/tab-user.png",
        "selectedIconPath": "static/tab-user-active.png"
      }
    ]
  }
}

tabBar页面有一些特殊限制:

  • 不能使用navigateTo跳转到tabBar页面,必须使用switchTab
  • tabBar页面在切换时不会重新加载,会保持之前的状态

路由传参的多种方式

除了通过url传递简单参数外,还可以使用以下方式传递复杂数据:

  1. 全局变量方式
// 发送页面
uni.navigateTo({
  url: '/pages/detail/detail',
  success: function(res) {
    res.eventChannel.emit('acceptData', {data: '复杂数据'});
  }
});

// 接收页面
onLoad(options) {
  const eventChannel = this.getOpenerEventChannel();
  eventChannel.on('acceptData', function(data) {
    console.log(data); // {data: '复杂数据'}
  });
}
  1. Vuex状态管理
// store.js
state: {
  routeParams: {}
},
mutations: {
  setRouteParams(state, params) {
    state.routeParams = params;
  }
}

// 发送页面
this.$store.commit('setRouteParams', {id: 123});
uni.navigateTo({url: '/pages/detail/detail'});

// 接收页面
computed: {
  params() {
    return this.$store.state.routeParams;
  }
}

路由拦截与权限控制

在实际项目中,经常需要对路由跳转进行拦截,实现登录验证等权限控制功能。可以通过重写路由方法实现:

// 封装路由跳转方法
const myNavigateTo = (options) => {
  if (options.url.indexOf('/pages/member/') !== -1) {
    if (!uni.getStorageSync('token')) {
      uni.showToast({title: '请先登录', icon: 'none'});
      uni.navigateTo({url: '/pages/login/login'});
      return;
    }
  }
  uni.navigateTo(options);
};

// 使用封装的方法
myNavigateTo({
  url: '/pages/member/center'
});

路由动画与自定义效果

uni-app支持通过配置实现页面跳转动画效果:

uni.navigateTo({
  url: '/pages/detail/detail',
  animationType: 'slide-in-right',
  animationDuration: 300
});

支持的动画类型包括:

  • slide-in-right - 从右侧横向滑动进入
  • slide-in-left - 从左侧横向滑动进入
  • slide-in-top - 从上侧竖向滑动进入
  • slide-in-bottom - 从下侧竖向滑动进入
  • fade-in - 淡入
  • zoom-out - 放大进入
  • zoom-fade-out - 放大淡入
  • pop-in - 从右侧平移进入

路由API的进阶用法

  1. 获取当前路由栈信息
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
console.log(currentPage.route); // 当前页面路径
  1. 动态修改页面标题
uni.setNavigationBarTitle({
  title: '新标题'
});
  1. 监听路由变化
// 在App.vue中
onShow() {
  const pages = getCurrentPages();
  const currentPage = pages[pages.length - 1];
  this.$bus.$emit('routeChange', currentPage.route);
}

常见问题与解决方案

  1. 页面返回刷新问题
// 前一个页面添加监听
onShow() {
  if (this.$refs.list) {
    this.$refs.list.refresh();
  }
}
  1. 页面栈超过10层限制
// 使用redirectTo代替navigateTo
uni.redirectTo({
  url: '/pages/newpage/newpage'
});
  1. tabBar红点提示
uni.showTabBarRedDot({
  index: 1 // tabBar的索引
});
  1. 动态隐藏tabBar
uni.hideTabBar({
  animation: true
});

跨平台路由差异处理

不同平台的路由行为可能有差异,需要进行兼容处理:

// 判断平台
const isH5 = process.env.VUE_APP_PLATFORM === 'h5';

// 平台特定处理
if (isH5) {
  // H5特有的路由逻辑
  window.addEventListener('popstate', this.handlePopState);
} else {
  // 小程序/App的路由逻辑
  uni.onAppRoute((res) => {
    console.log(res.path);
  });
}

路由性能优化技巧

  1. 预加载页面
uni.preloadPage({
  url: '/pages/detail/detail'
});
  1. 分包加载
// pages.json
{
  "subPackages": [
    {
      "root": "pages/sub",
      "pages": [
        {
          "path": "moduleA",
          "style": {}
        }
      ]
    }
  ]
}
  1. 路由懒加载
// 动态导入组件
components: {
  'lazy-component': () => import('@/components/lazy-component.vue')
}

路由与页面生命周期的关系

理解路由跳转时页面生命周期的触发顺序很重要:

  1. 从A页面navigateTo到B页面:

    • A页面:onHide
    • B页面:onLoad → onShow → onReady
  2. 从B页面navigateBack到A页面:

    • B页面:onUnload
    • A页面:onShow
  3. 使用redirectTo时:

    • 原页面:onUnload
    • 新页面:onLoad → onShow → onReady

路由参数的安全处理

处理路由参数时需要注意安全性:

  1. 参数校验
onLoad(options) {
  const id = parseInt(options.id);
  if (isNaN(id) || id <= 0) {
    uni.redirectTo({url: '/pages/error/error'});
    return;
  }
  this.loadData(id);
}
  1. 参数编码解码
// 发送时编码
uni.navigateTo({
  url: `/pages/detail/detail?title=${encodeURIComponent('包含特殊字符的参数&value=1')}`
});

// 接收时解码
onLoad(options) {
  const title = decodeURIComponent(options.title);
}

路由与页面通信的高级模式

  1. 使用EventBus进行跨页面通信
// 发送页面
this.$bus.$emit('data-update', {newData: 'value'});

// 接收页面
created() {
  this.$bus.$on('data-update', this.handleDataUpdate);
},
beforeDestroy() {
  this.$bus.$off('data-update', this.handleDataUpdate);
}
  1. 使用Vuex进行状态共享
// 发送页面
this.$store.commit('updateData', payload);

// 接收页面
computed: {
  sharedData() {
    return this.$store.state.sharedData;
  }
}

路由钩子的实现方式

虽然uni-app没有直接提供路由钩子,但可以通过以下方式模拟:

  1. 全局路由钩子
// main.js
const originalNavigateTo = uni.navigateTo;
uni.navigateTo = function(options) {
  console.log('即将跳转到:', options.url);
  originalNavigateTo.call(uni, options);
};
  1. 页面级路由钩子
// 在页面中
onShow() {
  if (this.$options.routeHook && this.$options.routeHook.beforeEnter) {
    this.$options.routeHook.beforeEnter.call(this);
  }
}

路由与页面滚动位置

处理页面滚动位置是常见的需求:

  1. 保存滚动位置
onPageScroll(e) {
  this.scrollTop = e.scrollTop;
},
onHide() {
  uni.setStorageSync('pageScroll_' + this.$route.path, this.scrollTop);
}
  1. 恢复滚动位置
onShow() {
  const savedPosition = uni.getStorageSync('pageScroll_' + this.$route.path);
  if (savedPosition) {
    uni.pageScrollTo({
      scrollTop: savedPosition,
      duration: 0
    });
  }
}

动态路由与权限控制

根据用户权限动态生成路由表:

// 根据权限过滤路由
function filterRoutes(routes, permissions) {
  return routes.filter(route => {
    if (route.meta && route.meta.permission) {
      return permissions.includes(route.meta.permission);
    }
    return true;
  });
}

// 动态修改pages.json
const dynamicRoutes = filterRoutes(allRoutes, userPermissions);
uni.setTabBarItems({
  items: dynamicRoutes.filter(r => r.isTab).map(r => ({
    pagePath: r.path,
    text: r.title,
    iconPath: r.icon,
    selectedIconPath: r.selectedIcon
  }))
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌