Uniapp 中根据不同离开页面方式处理 `onHide` 的方法

Uniapp 中根据不同离开页面方式处理 onHide 的方法

在 Uniapp 开发中,onHide 生命周期会在页面隐藏时触发,但默认无法直接区分用户是通过何种方式离开页面的。不过我们可以通过组合其他钩子函数和路由事件来实现对不同离开方式的识别和处理。

一、常见的页面离开方式

  1. 路由跳转

    • 使用 uni.navigateTo 跳转到非 tab 页面
    • 使用 uni.switchTab 跳转到 tab 页面
    • 使用 uni.redirectTo 重定向到其他页面
    • 使用 uni.reLaunch 关闭所有页面并跳转
  2. 返回操作

    • 点击手机物理返回键
    • 点击页面中的返回按钮(如 uni.navigateBack
    • 小程序左上角的导航栏返回按钮
  3. 其他场景

    • 小程序被切入后台(onHide 会触发)
    • 页面被组件覆盖(如弹窗、模态框)

二、区分离开方式的实现方法

1. 通过路由参数标记跳转方式
javascript 复制代码
export default {
  data() {
    return {
      leaveType: '' // 记录离开方式
    }
  },
  
  onLoad(options) {
    // 从参数中获取离开方式标记
    if (options.leaveType) {
      this.leaveType = options.leaveType;
    }
  },
  
  onHide() {
    this.handleLeavePage();
  },
  
  methods: {
    // 处理不同离开方式
    handleLeavePage() {
      switch (this.leaveType) {
        case 'navigateTo':
          console.log('通过 navigateTo 离开');
          // 保存临时数据
          break;
        case 'switchTab':
          console.log('切换到 Tab 页面');
          // 暂停定时器
          break;
        case 'navigateBack':
          console.log('返回上一页');
          // 提交未保存数据
          break;
        default:
          console.log('未知方式离开');
      }
    },
    
    // 页面内按钮跳转示例
    goToNextPage() {
      uni.navigateTo({
        url: '/pages/next-page',
        // 携带离开方式标记
        events: {
          // 可接收目标页面返回的数据
        },
        success: (res) => {
          // 跳转成功后执行
        }
      });
    }
  }
}
2. 使用全局状态管理(Vuex/Pinia)记录操作
javascript 复制代码
// store/index.js (使用 Pinia)
import { defineStore } from 'pinia'

export const useAppStore = defineStore('app', {
  state: () => ({
    lastLeaveType: ''
  }),
  actions: {
    setLeaveType(type) {
      this.lastLeaveType = type;
    }
  }
})

// 页面中使用
<template>
  <view>
    <button @click="goBack">返回上一页</button>
    <button @click="goToTab">切换到 Tab 页</button>
  </view>
</template>

<script>
import { useAppStore } from '@/store'

export default {
  setup() {
    const appStore = useAppStore();
    
    const goBack = () => {
      appStore.setLeaveType('navigateBack');
      uni.navigateBack();
    }
    
    const goToTab = () => {
      appStore.setLeaveType('switchTab');
      uni.switchTab({ url: '/pages/tab/index' });
    }
    
    return {
      goBack,
      goToTab
    }
  },
  
  onHide() {
    const leaveType = appStore.lastLeaveType;
    if (leaveType === 'navigateBack') {
      // 处理返回操作
    } else if (leaveType === 'switchTab') {
      // 处理切换 Tab 操作
    }
  }
}
</script>
3. 监听物理返回键和导航栏返回事件
javascript 复制代码
export default {
  data() {
    return {
      isBackAction: false,
      isTabSwitch: false
    }
  },
  
  onLoad() {
    // 监听物理返回键
    uni.onBackPress(() => {
      this.isBackAction = true;
      // 这里可以控制是否允许返回
      return false; // 阻止默认返回行为
    });
    
    // 监听页面切换到 Tab 的事件(需要配合全局监听)
    // 可在 App.vue 中监听 tab 切换
  },
  
  onShow() {
    // 每次显示时重置标记
    this.isBackAction = false;
    this.isTabSwitch = false;
  },
  
  onHide() {
    if (this.isBackAction) {
      console.log('用户点击了返回按钮');
      this.saveBeforeBack();
    } else if (this.isTabSwitch) {
      console.log('切换到了 Tab 页面');
      this.pauseProcess();
    } else {
      console.log('其他方式离开页面');
    }
  },
  
  methods: {
    // 跳转到非 Tab 页面
    goToOtherPage() {
      uni.navigateTo({ url: '/pages/other' });
    },
    
    // 切换到 Tab 页面(需在 App.vue 中标记)
    switchToTab() {
      getApp().globalData.isTabSwitch = true;
      uni.switchTab({ url: '/pages/tab/index' });
    }
  }
}
4. 在 App.vue 中全局监听路由事件
javascript 复制代码
// App.vue
export default {
  onLaunch() {
    console.log('App Launch');
    this.globalData = {
      lastRouteAction: '' // 记录最后一次路由操作
    }
    
    // 监听路由变化
    uni.onAppRoute((obj) => {
      const { path, query } = obj;
      
      // 判断路由操作类型
      if (path.startsWith('/pages/tab/')) {
        this.globalData.lastRouteAction = 'switchTab';
      } else if (query._navigateBack) {
        this.globalData.lastRouteAction = 'navigateBack';
      } else {
        this.globalData.lastRouteAction = 'navigateTo';
      }
    });
  },
  
  onShow() {
    console.log('App Show');
  },
  
  onHide() {
    console.log('App Hide');
  }
}

// 页面中使用
export default {
  onHide() {
    const lastAction = getApp().globalData.lastRouteAction;
    switch (lastAction) {
      case 'switchTab':
        // 处理 Tab 切换
        break;
      case 'navigateBack':
        // 处理返回
        break;
      case 'navigateTo':
        // 处理普通跳转
        break;
    }
  }
}

三、不同场景的处理建议

离开方式 检测方法 典型处理场景
普通跳转(navigateTo) 通过路由参数或全局状态标记 保存临时表单数据、暂停非紧急任务
返回(navigateBack) 监听物理返回键或路由参数 提交未保存内容、提示用户确认离开
切换 Tab(switchTab) 全局监听或在跳转时标记 暂停实时数据更新、保存页面滚动位置
小程序切后台 结合 onHide 和 onAppHide 事件 暂停音频播放、保存当前操作进度
重定向(redirectTo) 通过路由参数或全局状态标记 清除临时缓存、释放资源

四、最佳实践

  1. 组合使用多种检测方法:根据项目复杂度选择合适的检测方式,复杂场景可结合全局状态和路由参数

  2. 避免过度标记:只对关键操作进行标记,避免增加过多代码复杂度

  3. 重置状态 :在 onShow 中重置标记状态,确保每次页面显示时状态干净

  4. 性能考虑 :避免在 onHide 中执行耗时操作,优先使用异步处理或标记待处理任务

javascript 复制代码
export default {
  onHide() {
    // 标记需要处理的任务,而非直接执行
    this.pendingTasks = {
      saveData: true,
      pauseTimer: true
    };
  },
  
  onUnload() {
    // 页面卸载时执行最终处理
    if (this.pendingTasks.saveData) {
      this.saveAllData();
    }
  }
}

通过以上方法,你可以在 onHide 中区分不同的离开方式,并执行针对性的处理逻辑,提升用户体验和应用稳定性。

相关推荐
玺同学44 分钟前
从卡顿到流畅:前端渲染性能深度解析与实战指南
前端·javascript·性能优化
我是谁谁1 小时前
一篇文章让你学透在Vue 3 中watch 和 watchEffect的区别
javascript
光影少年1 小时前
vuex中的辅助函数怎样使用
前端·javascript
teeeeeeemo1 小时前
JS数据类型检测方法总结
开发语言·前端·javascript·笔记
懒大王、1 小时前
Vue添加图片作为水印
前端·javascript·vue.js
3Katrina1 小时前
《JavaScript this 指向深度剖析:从基础到复杂场景实战》
前端·javascript
暖苏1 小时前
Vue.js第一节
前端·javascript·css·vue.js·ecmascript
white.tie2 小时前
一个手机请求头的随机库
开发语言·javascript·python
萌萌哒草头将军3 小时前
⚡️⚡️⚡️ 开源了!原来 Vite 加载图片还可以这样啊!🚀🚀🚀
javascript·vue.js·react.js
咚咚咚ddd3 小时前
前端基建:使用plus api实现app通知权限管理
前端·javascript·前端工程化