VRouter logo


A Flutter package that makes navigation and routing easy.

Learn more at vrouter.dev

Here are a few things that this package will make easy:

  • Automated web url handling
  • Nesting routes
  • Transition
  • Advanced url naming
  • Reacting to route changing
  • Customizable pop events
  • And much more...

Overview

The goal of this package is to implement a routing system which is similar to the one in Vue.js (named vue router).

The idea is to use the VRouter widget on top of you app, and use VRouteElement to create you routes.

VRouter(
  routes: [
    // This matches the path '/login'
    VStacked(
      path: '/login',
      widget: LoginWidget(),
    ),

    VStacked(
      // This matches the path '/in'
      path: '/in',
      widget: MyScaffold(),

      subroutes: [
        // VChild are accessible via VRouteElementData.vChild
        VChild(
          // This matches the path '/in/profile/:id'
          // :id can be any word and will by accessible as a path parameter
          path: 'profile/:id',
          widget: ProfileWidget(),
        ),
        VChild(
          // This matches the path '/settings'
          path: '/settings',
          widget: ProfileWidget(),
        ),
      ],
    ),

    VRouteRedirector(
      // This matches any path
      path: ':_(.*)',
      // We redirect to /login
      redirectTo: '/login',
    )
  ],
)

VRouteElements

VStacked

VStacked is a VRouteElement which is stacked on the parent VRouteElement. For example:

VStacked(
  path: '/login', widget: LoginWidget(),
  subroutes: [
    VStacked(path: '/home', widget: HomeWidget()),
  ]
)

Here the HomeWidget will be stacked on top of the LoginWidget.

VChild

VChild are useful when nesting widgets. You can access them using VRouteElementData.vChild

For example, for the example above:

class MyScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: VRouteElementData.of(context).vChild,
    );
  }
}

VRouteRedirector

This is useful when you want a VRouteElement which only redirects

Useful notions

If you want detailed explanations of the notions bellow, please have a look at the vrouter.dev website.

Programmatic Navigation

Use VRouterData to access VRouter methods which allow you to navigate:

// Pushing a new url
VRouterData.of(context).push('/home');

// Pushing a named route
VRouterData.of(context).pushNamed('home');

// Pushing an external route
VRouterData.of(context).pushExternal('google.com');

Named route

Naming a route is simple and allows for simpler navigation, just use the name attribute of any VRouteElement.

Path parameters

You will often need to match with a certain path pattern to the same route. To easily achieve this, you can use path parameters. To use them you just need to insert :parameterName in the url.

VRouter configuration

VRouter(
  routes: [
    VStacked(
      path: '/user/:id',
      widget: UserWidget(),
    ),
  ],
)

Access the path parameters in you widgets:

class UserWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Use VRouteElement to access general information about the route
    print('The current id is: ${VRouteData.of(context).pathParameters['id']}');

    // Use VRouteElementData to data which belong to this VRouteElement
    return Text('User id is ${VRouteElementData.of(context).pathParameters['id']}');
  }
}

Transitions

You can either specify a default transition in VRouter, or a transition specific to a given route by specifying the transition in the last VRouteElement in the route

VRouter(
  // This transition will be applied to every route
  buildTransition: (animation1, _, child) =>
      FadeTransition(opacity: animation1, child: child),
  routes: [
    // No transition is specified, so the default one will play for '/user'
    VStacked(
      path: '/user',
      widget: ProfileWidget(),
      subroutes: [
        // The custom transition will be played when accessing '/user/likes'
        VChild(
          path: 'likes',
          widget: LikesWidget(),
          buildTransition: (animation1, _, child) =>
              ScaleTransition(scale: animation1, child: child),
        )
      ],
    ),
    // No transition is specified, so the default one will play
    VStacked(path: '/settings', widget: SettingsWidget()),
  ],
);

Pop events

Pop event are handled by default: The last VStack of the route which path
is not null is remove.

VRouter logo

But you can also handle a pop event by yourself

VRouter(
  // Every pop event will call this
  onPop: (vRedirector) async {
    return vRedirector.push('/other'); // You can use vRedirector to redirect
  },
  routes: [
    VStacked(
      path: 'profile',
      // popping the path path /login will call this
      onPop: (vRedirector) async {
        vRedirector.stopRedirection(); // You can use vRedirector to stop the redirection
      },
      widget: ProfileWidget(),
    ),
  ],
)

VRouter allows you to have a fine grain control over navigation events.

Use the beforeLeave, beforeEnter, afterEnter or afterUpdate to catch navigation events, referring to the following navigation cycle to know in which order they happen:

  1. Call beforeLeave in all deactivated VNavigationGuard
  2. Call beforeLeave in the nest-most VRouteElement of the current route
  3. Call beforeLeave in the VRouter
  4. Call beforeEnter in the VRouter
  5. Call beforeEnter in the nest-most VRouteElement of the new route

## The history state got in beforeLeave are stored
## The state of the VRouter changes

  1. Call afterEnter in the VRouter
  2. Call afterEnter in the nest-most VRouteElement of the new route
  3. Call afterUpdate in all reused VNavigationGuard
  4. Call afterEnter in all initialized VNavigationGuard

In every before.. function, you can use the first argument to stop the
navigation using .stopNavigation()

Much more

There is so much more that this package can do, check out the example or have a look at the vrouter.dev website

Libraries

vrouter