Chapter 3. Navigation with Vue Router

A single page application is just that; a single page. Navigating between “pages” is not really possible in the traditional sense; you cannot just link to another page. Instead, you are linking to a route, which then loads (or mounts) a set of components that you define and renders them to the view in your browser.

In order to achieve this, a JavaScript library is needed to load the components that you defined per that route. The Vue Core Team has created an official routing library called, “Vue Router” that is automatically installed (if selected during setup) when working on a Vue CLI project. Other frameworks have their “own” libraries, but what makes Vue Router so special is that it is indeed developed and maintained by the Core Team. When Vue gets updated, there’s a good chance that Vue Router will as well. This means that Vue Router is guaranteed to work with all versions new or old of Vue.js.

React.js, for example, does not have an official routing library. There are of course “standard” or widely recommended libraries (like React Router 4) but none that are developed by the React team at Facebook. This is also the same for state management; Vue’s state management library is created and maintained by the Core Team. However, since React Router 4 is independent of React, there isn’t a guarantee that the two libraries will always work together.

Using Vue Router with Plain JavaScript

You don’t need to create a Webpack-enabled Vue.js application to use Vue Router. You can use Vue Router alongside the Vue.js library in a static HTML page. Just like the core Vue.js library, you can also install Vue Router with just a CDN.

<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

Note: The Vue Router library, as well as all other companion libraries, should be loaded after Vue.js.

index.html

<html>
  <head>
    <title>A static Vue.js Application with Vue Router</title>
    <!-- Vue.js -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <!-- Vue Router -->
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script src="js/app.js"></script>
  </head>

  <body>
    <div id="app">
      <h1>My App</h1>

      <ul>
        <li><router-link to="/page-one">Go to Page One</router-link><li>
        <li><router-link to="/page-two">Go to Page Two</router-link></li>
      </ul>

      <router-view></router-view>
    </div>
  </body>
</html>

The <router-link> component renders an anchor tag (<a href="#">) that links to that route. The <router-view /> component loads the component(s) or template(s) that you defined in your external JavaScript page.

js/app.js

const PageOne = {
  template: `
    <div>
      <p>I am the Page One component.</p>
    </div>
  `,
};

const PageTwo = {
  template: `
    <div>
      <p>I am the Page Two component.</p>
    </div>
  `,
};

const routes = [
  { path: '/page-one', component: PageOne },
  { path: '/page-two', component: PageTwo }
];

const router = new VueRouter({
  routes, // short for `routes: routes`
});

const app = new Vue({
  router,
  stat,
}).$mount('#app');

Note: The JavaScript code is written in ES6. You will need to add a compiler like Babel if you want to run this in the browser. However, you can easily convert this ES6 code to the more supported ES5 syntax, which doesn’t require Babel.

Using Vue Router Within a Module System (Webpack, Node, Vue CLI)

Vue Router is most useful when working with a Webpack, Node.js, or a module-based single page application systems like the apps created with Vue CLI 3. Chapter 2: Scaffolding Projects With Vue CLI 3 goes over creating a Webpack built Vue.js application with Vue CLI 3. If you haven’t read Chapter 2 yet, it’s recommended that you read it so you have a general understanding of single file components and Webpack.

If you generated a project with Vue CLI 3 or the Vue CLI UI, there is an option to include Vue Router during the setup process. If you did not select Vue Router during the setup process, you can still import it via NPM or Yarn and import them into your project with ECMAScript6 (ES6).

$ npm install vue-router --save
# or
$ yarn add vue-router

In the src directory of your application, create a router.js file. This file will store all of your application’s routes. In this file, you can define which component gets mounted when a certain route is visited. For now, leave this file blank. Let’s add it to the main Vue Instance in the main.js file.

In your main.js file, you should see something similar to the snippet below.

main.js

import Vue from 'vue';
import App from './App.vue';
import './registerServiceWorker';

Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
}).$mount('#app');

This is the bare bones Vue Instance of the application. Go ahead and import your router file and add it as a dependency in your instance.

main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import './registerServiceWorker';

Vue.config.productionTip = false;

new Vue({
  router, // short for router: router
  render: h => h(App),
}).$mount('#app');

Save this file. Your router is now part of the instance and you can now create routes globally in the application. Before you start adding routes, you need to add the <router-view /> component to the App.vue file. This is where the component (per route) gets mounted and injected into.

App.vue

<template>
  <div id="app"><!-- el in the main Vue Instance -->
    <router-view/><!-- components per routes get mounted here -->
  </div>
</template>

Now that your router is set up, let’s flesh out the router.js file. The first thing that you will need to do is import Vue and the vue-router library.

router.js

import Vue from 'vue';
import Router from 'vue-router';

Next, we want to tell Vue to use the vue-router library.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

Vue.use(Router);

Next, let’s export the Router object with a routes property.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

Vue.use(Router);

export default new Router({
  routes: [],
});

This routes object is where you will add objects that define the route. The properties that the route object takes are path: the URL path itself, name: the name of the route (more of this later), and component: The actual component that gets mounted with the path is visited in the URL bar.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
  ],
});

The route object above is loading the Home component when the root route is accessed (ex: localhost:3000/). To add more routes, you will need to import the route and create another object in the routes array.

Routing to Another Route

In a previous section, you linked another route via plan ES6 JavaScript with the <router-link /> component. The <router-link /> component accepts a single prop: to. The to prop is equivalent to href with the <a> HTML tag. In fact, <router-link /> actually gets rendered as an anchor tag with a href attribute.

Routing Using String Paths

The easiest way to link to another route is to pass in a string to the to prop. The string directory corresponds to the path property in the route object in the router.js

<router-link to="/about">To the About Page</router-link>

The router-link above renders out to a <a> tag:

<a href="/about">To the About Page</a>

Routing Using Names and Parameters

Sometimes it’s easier to remember a name of a route versus the string URL path. You can link to another route by using the name property in the route object.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import AboutMe from './views/About.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'about',
      component: AboutMe,
    },
  ],
});

To link to a route using the name, pass in an object into the to prop:

<router-link :to="{ name: 'about'}">To the About Me Page</router-link>

You can also pass in parameters into your route if you have dynamic routes or a page with different data.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import SingleProject from './views/SingleProject.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/work/:projectId',
      name: 'singleProject',
      component: SingleProject,
    },
  ],
});
<router-link :to="{ name: 'singleProject', params: { projectId: 'some-project' }}">To a Single Project</router-link>

Routing with Named Views

A single route can also have many components associated with it. This is useful if you want to add another <router-view /> to a specific route, like the main view and a sidebar, for example.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Main from './views/Main.vue';
import Sidebar from './views/Sidebar.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      components: {
        default: Main,
        sidebar: Sidebar,
      },
    },
  ],
});

In the snippet above, you are importing the Main and Sidebar components and assigning them to a name. In this case, the default component for the / route is Main. When we link to a route with multiple components, it’ll mount both components as one.

<div id="app">
  <router-view/><!-- mount the default component, which is "Main" -->
  <router-view name="sidebar"/><!-- mounts the sidebar -->
</div>

Using Aliases and Redirects

Let’s talk about web applications like GitHub and Twitter for a second. Notice anything about them? Well, it depends whether or not you are logged into those services. If you are not logged in, you will see the home page with a login form. If you are logged in, you will see your dashboard or timeline.

Granted, GitHub and Twitter are not using Vue.js (yet...) but this type of functionality can be achieved with route aliases. To add an alias, just add the alias property to a route object in your router.js.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Login from './views/Login.vue';
import Dashboard from './views/Dashboard.vue';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      component: Login,
      name: 'login',
    },
    {
      path: '/dashboard',
      component: Dashboard,
      name: 'dashboard',
      alias: '/', // Alias right here
    },
  ],
});

With the alias above, you are telling Vue.js to load the /dashboard route and it’s components but keep the URL as /'. In your code, you will add arouter-linkbut link it to the/dashboard` route; Vue Router will handle the rest.

<router-link to="/dashboard">To Dashboard</router-link>
<!-- Link to the dashboard route, load it's components but keep the URL as `/` -->

Similar to alias, redirects will redirect the linked route to another route when visited.

router.js

export default new Router({
  routes: [
    {
      path: '/',
      redirect: '/dashboard
    },
  ],
});
<router-link to="/">To Dashboard</router-link>
<!-- Link to the main route, but redirect to 'dashboard` -->

If you are familiar with Apache rewrite rules, you can kind of think of them that way. They’re just handled within your application using Vue Router.

History Mode and Server Configurations

Currently, in your application, the URLs are prefixed with /#/ this is the default mode which is also known as “hash mode”. When in hash mode, Vue.js uses the /#/ to simulate a URL so the page won’t be reloaded when the URL changes. However, you can change this by enabling history mode. In history mode, Vue Router takes advantage of the ‘history.pushState` API to prevent the page from reloading.

To enable history mode, just add the mode attribute with a value of history to the VueRouter object.

router.js

export default new Router({
  mode: 'history', // Down here!
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
  ],
});

This removes the hash in the URL and makes the URL path look “normal” as desired. However, since it’s a singe page application, in history mode and without server configurations, navigating to a route will result in a 404 page. To fix this you can add the server configurations provided in the official Vue Router documentation.

Apache

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

Nginx

location / {
  try_files $uri $uri/ /index.html;
}

Native Node.js

const http = require('http');
const fs = require('fs');
const httpPort = 80;

http
  .createServer((req, res) => {
    fs.readFile('index.htm', 'utf-8', (err, content) => {
      if (err) {
        console.log('We cannot open "index.htm" file.');
      }

      res.writeHead(200, {
        'Content-Type': 'text/html; charset=utf-8',
      });

      res.end(content);
    });
  })
  .listen(httpPort, () => {
    console.log('Server listening on: http://localhost:%s', httpPort);
  });

Internet Information Services (IIS)

  1. Install URL Rewrite.
  2. Create a web.config file in the root directory of your site with the following:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Cady

rewrite {
  regexp .*
  to {path} /
}

Firebase Hosting

Add the following to your firebase.json:

{
  "hosting": {
    "public": "dist",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

404 Fallback

There is one caveat to this though: Your server will no longer report 404 errors since all of your paths now redirect to the index route. You can get around this by creating a 404 component that displays if any route does not route. Create another route object with a wildcard (*) and include the 404 component to mount if a component is not found.

router.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home';
import NotFound from './views/NotFound';

Vue.use(Router);

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
    {
      path: '*',
      component: NotFound,
    },
  ],
});

Conclusion

Vue Router is a great library to navigate between the different views or “pages” of your application. All of your routes live inside one router.js file that gets injected as a dependency into your Vue Instance. As stated above, there are different types of routes that you can have including named routes, dynamic routes, redirects, alias, and stringed routes.

Unlike its competitors, Vue Router is a first party proprietary router created by the Vue.js Core Team. Since it’s the first party router for Vue.js, Vue Router is guaranteed to work with the latest versions of the core Vue.js library. With React, for instance, the unofficial “official” recommendation is React Router 4, which could change at any time and has a higher chance of introducing breaking changes to your application. With that being said, you do not need to use Vue Router in your application. You can use a third party Vue.js router. However, it is not recommended.

The Vue Router documentation (as well as all of the other docs) is written and maintained by Chris Fritz and Sarah Drasner.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.100.120