全局监听路由堆栈变化

老孟导读:很多时候我们需要监听路由堆栈的变化,这样可以自定义路由堆栈、方便分析异常日志等。

监听路由堆栈的变化使用 RouteObserver ,首先在 MaterialApp 组件中添加 navigatorObservers

void main() {
  runApp(MyApp());
}

RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      navigatorObservers: [routeObserver],
      home: HomePage(),
    );
  }
}

监听页面设置如下:

class ARouteObserverDemo extends StatefulWidget {
  @override
  _RouteObserverDemoState createState() => _RouteObserverDemoState();
}

class _RouteObserverDemoState extends State<ARouteObserverDemo> with RouteAware {

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: RaisedButton(
          child: Text('A RouteObserver'),
          onPressed: () {
            Navigator.of(context).pushNamed('/BRouteObserver');
          },
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    routeObserver.unsubscribe(this);
  }

  @override
  void didPush() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPush route: $route');
  }

  @override
  void didPopNext() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPopNext route: $route');
  }

  @override
  void didPushNext() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPushNext route: $route');
  }

  @override
  void didPop() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPop route: $route');
  }

}

其中 didPush、didPushNext、didPopNext、didPop 为路由堆栈变化的回调。

从 A 页面跳转到 ARouteObserverDemo 页面,日志输出如下:

flutter: A-didPush route: /ARouteObserver

进入此页面只调用了 didPush。

从 ARouteObserverDemo 页面跳转到 BRouteObserverDemo 页面(同 ARouteObserverDemo 页面,设置了监听),日志输出如下:

flutter: A-didPushNext route: /ARouteObserver
flutter: B-didPush route: /BRouteObserver

先调用了 ARouteObserverDemo 页面的 didPushNext,然后调用了 BRouteObserverDemo 页面的 didPush。

从 BRouteObserverDemo 页面执行 pop 返回 ARouteObserverDemo 页面,日志输出如下:

flutter: A-didPopNext route: /ARouteObserver
flutter: B-didPop route: /BRouteObserver

先调用了 ARouteObserverDemo 页面的 didPopNext,然后调用了 BRouteObserverDemo 页面的 didPop。

上面的案例仅仅是页面级别的路由堆栈变化,如果想知道整个应用程序路由堆栈变化如何处理?

一种方法是写一个监听路由堆栈的基类,所有页面继承此基类。此方法对源代码的侵入性非常高。

还有一种方法是自定义 RouteObserver,继承RouteObserver并重写其中的方法:

class MyRouteObserver<R extends Route<dynamic>> extends RouteObserver<R> {
  @override
  void didPush(Route route, Route previousRoute) {
    super.didPush(route, previousRoute);
    print('didPush route: $route,previousRoute:$previousRoute');
  }

  @override
  void didPop(Route route, Route previousRoute) {
    super.didPop(route, previousRoute);
    print('didPop route: $route,previousRoute:$previousRoute');
  }

  @override
  void didReplace({Route newRoute, Route oldRoute}) {
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
    print('didReplace newRoute: $newRoute,oldRoute:$oldRoute');
  }

  @override
  void didRemove(Route route, Route previousRoute) {
    super.didRemove(route, previousRoute);
    print('didRemove route: $route,previousRoute:$previousRoute');
  }

  @override
  void didStartUserGesture(Route route, Route previousRoute) {
    super.didStartUserGesture(route, previousRoute);
    print('didStartUserGesture route: $route,previousRoute:$previousRoute');
  }

  @override
  void didStopUserGesture() {
    super.didStopUserGesture();
    print('didStopUserGesture');
  }
}

使用:

void main() {
  runApp(MyApp());
}

MyRouteObserver<PageRoute> myRouteObserver = MyRouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      navigatorObservers: [myRouteObserver],
      initialRoute: '/A',
      home: APage(),
    );
  }
}

此时从 A 页面 跳转到 B 页面,日志输出如下:

flutter: didPush route: MaterialPageRoute<dynamic>(RouteSettings("/B", 来自A), animation: AnimationController#6d429(▶ 0.000; for MaterialPageRoute<dynamic>(/B))),previousRoute:MaterialPageRoute<dynamic>(RouteSettings("/A", null), animation: AnimationController#e60f7(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/A)))

交流

交流

老孟Flutter博客(330个控件用法+实战入门系列文章):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

### 前端路由路径记忆的实现方式 前端路由路径记忆是一种用户体验优化机制,旨在记录用户的最后访问状态,在刷新页面或其他场景下恢复该状态。以下是其实现的核心原理和技术细节: #### 1. 使用 `sessionStorage` 或 `localStorage` 可以通过浏览器内置的存储 API 来保存当前路由路径。当用户离开页面或刷新时,可以从这些存储中读取上次的路径并跳转回原位置。 ```javascript // 记录当前路由路径到 sessionStorage 中 window.sessionStorage.setItem('lastRoute', window.location.pathname); // 页面加载时从 sessionStorage 获取上一次的路由路径 const lastRoute = window.sessionStorage.getItem('lastRoute'); if (lastRoute) { // 如果存在,则导航至该路径 window.history.pushState(null, null, lastRoute); } ``` 这种方式利用了浏览器本地存储的能力来持久化数据[^4]。 #### 2. Vue Router 的钩子函数配合使用 如果项目基于 Vue.js 构建,可以借助 Vue Router 提供的生命周期方法完成路径记忆功能。例如,可以在全局导航守卫中设置逻辑。 ```javascript import router from './router'; router.afterEach((to, from) => { // 将每次跳转的目标路径保存下来 window.sessionStorage.setItem('lastRoute', to.fullPath); }); router.beforeEach((to, from, next) => { const savedRoute = window.sessionStorage.getItem('lastRoute'); if (!savedRoute || to.path === '/') { next(); // 正常进入目标路径 } else { next(savedRoute); // 返回之前的位置 } }); ``` 上述代码片段展示了如何通过 Vue Router 钩子函数捕获和还原路径信息[^3]。 #### 3. 判断 URL 变化的差异处理 对于采用不同模式(如 Hash 和 History)构建的应用程序来说,其监听机制有所区别。Hash 模式的变更会触发特定事件 (`hashchange`) ,而 History 模式则需依赖其他手段检测变化情况。 - **Hash Mode**: 监听 `hashchange` 事件即可轻松获取最新地址栏中的哈希部分。 ```javascript window.addEventListener('hashchange', () => { console.log(`New hash value is ${location.hash}`); }); ``` - **History Mode**: 因为历史堆栈变化不会自动广播通知给开发者,因此需要手动查询 `location.pathname` 并结合定时轮询或者自定义解决方案来进行监控[^5]。 #### 总结说明 综合以上几种方案可以看出,无论是简单的单页应用还是复杂的多模块架构都可以找到适合自己的策略去达成路由路径的记忆效果。具体选择取决于实际需求以及框架支持程度等因素的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老孟Flutter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值