taro3.x-4.x路由拦截如何破?

✨点击上方关注☝️,追踪不迷路!

前言

"大家要是使用过京东的taro框架,都知道taro1.x是支持生命周期BeforeRouteLeave的,这个生命周期主要是用来监听用户返回页面或前进操作,用于弹出弹窗挽留用户等,那么假如你升级到了taro3或taro4,官方是不支持这个生命周期的,需要自己实现,本文主要就是介绍如何添加实现这个功能"

hook接口设计

接口名称

useBeforeRouteLeave(fn)

自定义 React 钩子,用于在 Taro 应用中拦截路由跳转,并在跳转前执行自定义逻辑(例如提示用户挽留)

使用场景

  • 在用户尝试离开当前页面时,提示挽留等。
  • 在特定条件下阻止路由跳转。

入参说明

参数 类型 是否必须 描述
fn Fuction 拦截逻辑回调函数,接收一个对象参数{ from, to, next }。

fn回调参数说明

参数 类型 是否必须 描述
from String 当前路由路径
to String 目标路由路径
next String 控制是否允许跳转的函数。flag=true允许跳转,flag=false阻止跳转。

返回值

无返回值

示例代码

js 复制代码
import useBeforeRouteLeave from './hooks/useBeforeRouteLeave';

function MyComponent() {
  useBeforeRouteLeave(({ from, to, next }) => {
    Taro.showModal({
      title: '是否离开?',
      confirmText: "确定"
    }).then(res=>{
      if (res.confirm) {
        next(true)
      } else {
        next(false)
      }
    })
  });

  return <div>My Component</div>;
}

代码逻辑设计

代码实现设计

js 复制代码
import { useEffect } from 'react'
import { useDidShow } from '@tarojs/taro'
import { history } from '@tarojs/router'
export default function useBeforeRouteLeave(fn) {
  let isunBlocked = false; // 标记拦截状态
  const from = history.location.pathname;
  const unblockWrap = () => {
    let unblock = history.block((tx) => {
      let to = tx.location.pathname
      const next = (flag) => {
        if (flag) {
          setTimeout(() => {
            unblock() // 解除拦截
            tx.retry() // 重试跳转
            isunBlocked = true; // 更新拦截状态
          })
        }
      }
      fn({ from, to, next })
    })
    return () => unblock(); // 返回清理函数
  }
  useEffect(() => { // 注册拦截
    return unblockWrap()
  })

  useDidShow(() => {
    if(isunBlocked) {
      isunBlocked = false;
      unblockWrap() // 重新启用拦截
    }
  })
}
  • 初始化拦截状态:isunBlocked 标记拦截状态,默认为false。
  • 注册拦截逻辑:通过history.block拦截路由跳转。
  • 执行回调:当拦截触发时,调用用户传入的fn函数。
  • 用户决策:用户通过next(flag)决定是否允许跳转。
  • 如果flag=true,解除拦截并重试跳转。
  • 如果flag=false,保持拦截状态。
  • 重新启用拦截:当页面重新显示时(useDidShow),重置拦截状态并重新注册拦截逻辑。

装饰器接口设计

接口名称

useBeforeRouteLeaveHoc()

自定义 React 高阶组件,用于在 Taro 应用中拦截路由跳转,并在跳转前执行自定义逻辑(例如提示挽留)

使用场景

  • 在用户尝试离开当前页面时,提示挽留等。
  • 在特定条件下阻止路由跳转。

装饰说明

给 class 类组件注入了生命周期beforeRouteLeave({from, to, next})

反参说明

参数 类型 是否必须 描述
from String 当前路由路径
to String 目标路由路径
next String 控制是否允许跳转的函数。flag=true允许跳转,flag=false阻止跳转。

示例代码

js 复制代码
import { Component } from 'react';
import Taro from "@tarojs/taro";
import { Button, View } from "@tarojs/components";
import { beforeRouteLeaveHoc } from '../../hoc/index';

@beforeRouteLeaveHoc()
class MyComponent extends Component {
  beforeRouteLeave({from, to, next}) {
    console.log('wen', 'beforeRouteLeave');
    Taro.showModal({
      title: 'beforeRouteLeave确定离开吗'
    }).then((res) => {
      if (res.confirm) {
        next(true);
      }

      if (res.cancel) {
        next(false);
      }
    });
  }
  handleRoute = () => {
    Taro.navigateTo({
      url: '/pages/index/index'
    })
  }
  render() {
    return (<View>
      <Button onClick={this.handleRoute.bind(this)}>跳转首页</Button>
    </View>)
  }
}

export default MyComponent;

代码逻辑设计

和hook方式代码逻辑设计一样

代码实现设计

js 复制代码
import { history } from '@tarojs/router';
/**
 * 路由离开拦截装饰器
 */
export function beforeRouteLeaveHoc() {
  return function (constructor) {
    return class extends constructor {
      constructor(...args) {
        super(...args);
        this.isunBlocked = false; // 拦截状态标记
        this.from = history.location.pathname; // 当前路径
        this.unblock = null; // 拦截器清理函数
      }

      componentDidMount() {
        if (super.componentDidMount) super.componentDidMount();
        this.setupRouteInterceptor();
      }

      componentDidShow() {
        if (super.componentDidShow) super.componentDidShow();
        if (this.isunBlocked) {
          this.isunBlocked = false;
          this.setupRouteInterceptor();
        }
      }

      componentWillUnmount() {
        if (super.componentWillUnmount) super.componentWillUnmount();
        if (this.unblock) this.unblock();
      }

      setupRouteInterceptor() {
        this.unblock = history.block((tx) => {
          const to = tx.location.pathname;
          const next = (flag) => {
            if (flag) {
              setTimeout(() => {
                if (this.unblock) this.unblock(); // 解除拦截
                tx.retry(); // 重试跳转
                this.isunBlocked = true; // 更新拦截状态
              });
            }
          };
          super.beforeRouteLeave && super.beforeRouteLeave({ from: this.from, to, next });
        });
      }
    };
  };
}

最后,创作不易请允许我插播一则自己开发的小程序广告,感兴趣可以访问体验:

【「合图图」产品介绍】

  • 主要功能为:本地添加相册图片进行无限长图高清拼接,各种布局拼接等

  • 安全:无后台服务无需登录,全程设备本地运行,隐私100%安全;

  • 高效:自由布局+实时预览,效果所见即所得;

  • 高清:秒生高清拼图,一键保存相册。

  • 立即体验 →合图图 或微信小程序搜索「合图图」

如果觉得本文有用 ,欢迎点个赞👍和收藏⭐支持我吧!

相关推荐
持久的棒棒君31 分钟前
启动electron桌面项目控制台输出中文时乱码解决
前端·javascript·electron
小离a_a1 小时前
使用原生css实现word目录样式,标题后面的...动态长度并始终在标题后方(生成点线)
前端·css
郭优秀的笔记2 小时前
抽奖程序web程序
前端·css·css3
布兰妮甜2 小时前
CSS Houdini 与 React 19 调度器:打造极致流畅的网页体验
前端·css·react.js·houdini
小小愿望2 小时前
ECharts 实战技巧:揭秘 X 轴末项标签 “莫名加粗” 之谜及破解之道
前端·echarts
小小愿望3 小时前
移动端浏览器中设置 100vh 却出现滚动条?
前端·javascript·css
fail_to_code3 小时前
请不要再只会回答宏任务和微任务了
前端
lpfasd1233 小时前
开发Chrome/Edge插件基本流程
前端·chrome·edge
练习前端两年半3 小时前
🚀 Vue3 源码深度解析:Diff算法的五步优化策略与最长递增子序列的巧妙应用
前端·vue.js