Navigation Router

With Framework7 & Vue.js, we are already composing our application with components. All we need to do is map our components to the routes. Here's a basic example:

<!-- Current View/Router -->
<f7-view>
  <!-- All pages are rendered inside of Pages -->
  <f7-pages>
    <!-- Initial Page -->
    <f7-page>
      ...
      <f7-link href="/about/">About App</f7-link>
      <f7-link href="/login/">Login</f7-link>
    </f7-page>
  </f7-pages>
</f7-view>

Now we need to map components to routes. It should be done in routes parameter on App Initialization

// Create Component for About page
Vue.component('page-about', {
    template: '<f7-page name="about">...</f7-page>'
})
// Create Component for Login page
Vue.component('page-login', {
    template: '<f7-page name="login">...</f7-page>'
})

// Init App
new Vue({
    el: '#app',
    framework7: {
        root: '#app',
        // Map routes
        routes: [
            {
                path: '/about/',
                component: 'page-about'
            },
            {
                path: '/login/',
                component: 'page-login'
            }
        ]
    }
})

If you use single file components (with Webpack or Browserify):

<!-- about.vue -->
<template>
  <f7-page name="about">
    <!-- Page content -->
  </f7-page>
</template>
<script>
  export default {}
</script>

<!-- login.vue -->
<template>
  <f7-page name="login">
    <!-- Page content -->
  </f7-page>
</template>
<script>
  export default {}
</script>
import AboutPage from 'about.vue'
import LoginPage from 'login.vue'

// Init App
new Vue({
    el: '#app',
    framework7: {
        root: '#app',
        // Map routes
        routes: [
            {
                path: '/about/',
                component: AboutPage
            },
            {
                path: '/login/',
                component: LoginPage
            }
        ]
    }
})
  • Note that route components are intended to load Page components only. If you want to load other components in a route, they must be added as nested routes within a page route.

  • All pages are rendered inside of the Pages component of the current (or specified) View

  • Only one Pages component is allowed inside of one View

  • You may have as many Views as required (e.g. in Popup, in Side Panels)

Dynamic Route Matching

Very often we will need to map routes with the given pattern to the same component. In specified routes we can use a dynamic segment in the path to achieve that.

Let's say we have the following link:

<f7-link href="/user/45/posts/28/?sort=first#opened">Read More</f7-link>

And the following pattern in specified route path:

import PostPage from 'post.vue'

// Init App
new Vue({
    el: '#app',
    framework7: {
        root: '#app',
        // Map routes
        routes: [
            {
                // We can use pattern here:
                path: '/user/:userId/posts/:postId',
                component: PostPage
            }
        ]
    }
})

In this case we have access to $route component property that we can use, e.g. in post.vue:

<!-- post.vue -->
<template>
  <f7-page>
    <f7-navbar title="Post"></f7-navbar>
    <ul>
      <li>Route: {{$route.route}}</li>
      <li>Url: {{$route.url}}</li>
      <li>Path: {{$route.path}}</li>
      <li>User ID: {{$route.params.userId}}</li>
      <li>Post ID: {{$route.params.postId}}</li>
      <li>Query: {{JSON.stringify($route.query)}}</li>
      <li>Hash: {{$route.hash}}
    </ul>
    <!-- $route.params are also passed as component props: -->
    <p>User ID: {{userId}}</p>
    <p>Post ID: {{postId}}</p>
  </f7-page>
</template>
<script>
  <!-- $route.params are also passed as component props: -->
  export default {
    props: ['userId', 'postId']
  }
</script>

And the output will be:

...
<ul>
  <li>Route: /user/:userId/posts/:postId</li>
  <li>Url: /user/45/posts/28/?sort=first#opened</li>
  <li>Path: /user/45/posts/28/</li>
  <li>User ID: 45</li>
  <li>Post ID: 28</li>
  <li>Query: {"sort":"first"}</li>
  <li>Hash: opened</li>
</ul>
<p>User ID: 45</p>
<p>Post ID: 28</p>
...

$route has the following properties:

$route.url Url of the loaded route/page
$route.params Object with route parameters (e.g. userId and postId in the example above)
$route.hash Route hash
$route.query Parsed query object
$route.path Route path (same as $route.url but without query and hash)
$route.route Matched route from specified routes parameter

Nested Routes

Child components within a page can be controlled via routes. Currently, this is only supported for tabs, but other components may be added in the future.

Tabs

The child components that render within a tab on a page can be controlled via routes. For example, consider these Vue components:

<!-- Tabs.vue -->
<template>
  <f7-page with-subnavbar>
    <f7-navbar back-link="Back" title="Tab Routes" sliding>
      <f7-subnavbar sliding>
        <f7-buttons>
          <f7-button route-tab-link="#tab1" href="/tabs/">Tab 1</f7-button>
          <f7-button route-tab-link="#tab2" href="/tabs/tab-2/">Tab 2</f7-button>
          <f7-button route-tab-link="#tab3" href="/tabs/tab-3/">Tab 3</f7-button>
        </f7-buttons>
      </f7-subnavbar>
    </f7-navbar>

    <f7-tabs>
      <f7-tab route-tab-id="tab1" />
      <f7-tab route-tab-id="tab2" />
      <f7-tab route-tab-id="tab3" />
    </f7-tabs>
  </f7-page>
</template>

<!-- Tab1Content.vue -->
<template>
    <p>Tab 1 Content</p>
</template>

<!-- Tab2Content.vue -->
<template>
    <p>Tab 2 Content</p>
</template>

<!-- Tab3Content.vue -->
<template>
    <p>Tab 3 Content</p>
</template>

With the route definitions below, the URL can control which tab content component gets rendered:

var routes = [
  ...
  {
    path: '/tabs/',
    component: Tabs,
    tabs: [
      {
        path: '/',
        tabId: 'tab1',
        component: Tab1Content
      },
      {
        path: '/tab-2/',
        tabId: 'tab2',
        component: Tab2Content
      },
      {
        path: '/tab-3/',
        tabId: 'tab3',
        component: Tab3Content
      }
    ]
  }
  ...
];

Here are the results for different URL paths beneath the Tabs page URL:

Url Result
/tabs/ Go to the tabs page (or stay on it if already there), show tab 1 as the selected tab f7-button, have the Tab1Content component rendered within the tab1 f7-tab, and make that the visible tab.
/tabs/tab-2/ Go to the tabs page (or stay on it if already there), show tab 2 as the selected tab f7-button, have the Tab1Content component rendered within the tab2 f7-tab, and make that the visible tab.
/tabs/tab-3/ Go to the tabs page (or stay on it if already there), show tab 2 as the selected tab f7-button, have the Tab1Content component rendered within the tab3 f7-tab, and make that the visible tab.

It is also possible to have multiple child routes for a tab route:

var routes = [
  ...
  {
    path: '/tabs/',
    component: Tabs,
    tabs: [
      {
        path: '/',
        tabId: 'tab1',
        component: Tab1Content
      },
      {
        path: '/tab-2/',
        tabId: 'tab2',
        component: Tab2Content
      },
      {
        path: '/tab-3/',
        tabId: 'tab3',
        routes: [
          {
            path: '/',
            component: Tab3Content
          },
          {
            path: '/tab3-alternate-content/',
            component: Tab3AlternateContent
          }
        ]
      }
    ]
  }
  ...
];

Here are the results for URL paths that target the different child routes of the tab3 route:

Url Result
/tabs/tab3/ Go to the tabs page and show the tab 3 as the selected tab and have the Tab3Content component rendered within it.
/tabs/tab-3/tab-3-alternate-content/ Go to the tabs page and show tab 3 as the selected tab and have the Tab3AlternateContent component rendered within it. If already on the tabs page with different tab content showing, replace the current tab3 content with Tab3AlternateContent.

Tab routes are also supported on Tabbars:

<!-- Tabbar.vue -->
<template>
  <f7-page tabbar-fixed>
    <f7-navbar back-link="Back" title="Tabbar Routes" sliding></f7-navbar>

    <f7-block tabs>
      <f7-tab route-tab-id="tab1" />
      <f7-tab route-tab-id="tab2" />
      <f7-tab route-tab-id="tab3" />
    </f7-block>

    <f7-toolbar tabbar labels>
      <f7-link href="/tabbar/" route-tab-link="#tab1" text="Tab 1"></f7-link>
      <f7-link href="/tabbar/tab-2/" route-tab-link="#tab2" text="Tab 2"></f7-link>
      <f7-link href="/tabbar/tab-3/" route-tab-link="#tab3" text="Tab 3"></f7-link>
    </f7-toolbar>

  </f7-page>
</template>

Router API

To access router instance and use Router API you can use special $router property of component:

<f7-link @click="$router.load({url: '/about/'})">About</f7-link>
<f7-link @click="$router.back()">Go Back</f7-link>

Please note, that $route and $router component properties are only available inside of custom page components (and their child components) that you load according to routes. In parent components (like in View, or where you init your Vue app instance) they are not accessible as your app may have few routers (Views) at a time. So in this case use access to initialized View Instance, e.g. $f7.views.main.router or $f7.mainView.router