Probably you've been using routers in the frontend world for a while, but... have you ever written one by yourself? Do you know the foundations of a router? It might seem like it just works, but under the hood a router must take care of several things.
A router is the component in charge of routing. We can define routing as the action of finding the way to multiple destinations. This applies to different areas.
For instance an elevator’s router will take you to the fifth floor if you press the button with the number 5 on it.
In web development, we can see two main areas of routing:
In this series we’ll look at how we can create our own front-end router with Vue.js, in order to understand the mechanics of a router.
Let's first create the components Home and Articles to use for the routes. The content is not important since is just for showing something on that route, something like the following is enough:
<!-- Home.vue -->
<template>
<div>Home</div>
</template>
<!-- Articles.vue -->
<template>
<div>Articles</div>
</template>
Since Vue.js is a component based framework, a simple way to create a router is by using a component. That way is more universal, since any front-end developer that has worked on any component based tool would be able to understand it.
Define the routes
Let’s start by creating a AppRouter.vue file which will be the Router component itself, with the definition of the routes:
<!-- Router.vue -->
<script>
import HomePage from "./HomePage";
import ArticlesPage from "./ArticlesPage";
const routes = {
"/": HomePage,
"/articles": ArticlesPage
};
</script>
I'm importing both HomePage and ArticlesPage components and creating a routes
object, which keys are the route path and the value is the component itself. Accessing the route in this way is simple and fast, since accessing an object property is a direct operation, just by doing routes["/"]
.
If you need more customisation, other ways to define them would be using an object as the value:
const routes = {
"/": {
component: HomePage,
default: true, // indicate if it's the default route
name: "root"
}
}
You could do it using an array as well, just as vue-router does. The array solution is more flexible while more complicated, since you’ll need later to loop through:
const routes = [
{
path: "/"
component: HomePage
}
}
// A simple way to get the component is using ES2015 array find method
const route = routes.find(route => route.path === "/");
Render the Router component
Once we have the routes set up, we need a way to render a component given a condition. Vue.js template provide us with dynamic components, which are perfect for our case.
A dynamic component allow us to easily hot-swap between components by using the special <component>
element, by using an is
property as a condition:
<template>
<component :is="routedComponent"></component>
</template>
Then we need to implement that condition. Since that condition will change depending on the route, a computed property fits perfectly for the purpose:
export default {
data() {
return { current: window.location.pathname };
},
computed: {
routedComponent() {
return routes[this.current];
}
}
};
The computed property would be a good place to return a component for a default route (a route that doesn't matches any), and it would be as easy as using an OR operator:
routedComponent() {
return routes[this.current] || DefaultComponent;
}
The final Router.vue component is:
<!-- Router.vue -->
<template>
<component :is="routedComponent"></component>
</template>
<script>
import HomePage from "./HomePage";
import ArticlesPage from "./ArticlesPage";
const routes = {
"/": HomePage,
"/articles": ArticlesPage
};
export default {
data() {
return { current: window.location.pathname };
},
computed: {
routedComponent() {
return routes[this.current];
}
}
};
</script>
As an alternative solution, render functions (or JSX) fits perfectly for this case, since rendering with render functions is dynamic by default. So you could rewrite the component in a Router.js file:
// Router.js
import HomePage from "./HomePage";
import ArticlesPage from "./ArticlesPage";
const routes = {
"/": HomePage,
"/articles": ArticlesPage
};
export default {
data() {
return { current: window.location.pathname };
},
computed: {
routedComponent() {
return routes[this.current];
}
},
render(createElement) {
return createElement(this.routedComponent);
}
};
Let's create an App.vue component as the root component for the application. Then import and register the router component:
<!-- App.vue -->
<template>
<div>
<app-router></app-router>
</div>
</template>
<script>
import AppRouter from "./AppRouter";
export default {
components: {
AppRouter
}
};
</script>
In the template, we place the <app-router>
tag which will be replaced by the component rendered by the router. In the script section, the Router is imported and added to the App component.
If you run the app and navigate between /
and /articles
by writing the routes in your browser's bar, you should see the router loads the corresponding component and its content.
To make it more convenient, let's add a couple of buttons and a method to navigate between routes in App.vue:
<!-- App.vue -->
<template>
<div>
<button @click="goTo('/articles')">Go to Articles</button>
<button @click="goTo('/')">Go to Home</button>
<app-router></app-router>
</div>
</template>
<script>
import AppRouter from "./AppRouter";
export default {
components: {
AppRouter
},
methods: {
goTo(route) {
window.location = route;
}
}
};
</script>
Try it again and click on the buttons, it should still work the same way.
Find here the code and demo from this article and try it yourself!
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.