Categories
JavaScript Vue

Vue Tips — Making Components Play Nice with Each Other

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how Vue components can play nice with each other.

Assign Attributes to the Right Elements

We can pass attributes from a grandparent component to a grandchild component by setting the inheritAttrs option to false , and then add v-bind='$attrs' to the child of the grandparent to pass the attributes of the grandparent to the grandchild.

For instance, we can write the following code to do that:

index.js :

Vue.component("foo", {  
  inheritAttrs: false,  
  template: `    
    <p v-bind='$attrs'>foo</p>    
  `  
});

new Vue({  
  el: "#app"  
});

index.html :

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <title>App</title>  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <foo class="foo"></foo>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then the foo class will be applied to the p element in foo since we set inheritAttrs to false in foo .

Use Browser Norms for Keyboard Navigation

We should follow the conventions for keyboard shortcuts for common operations if we’re going to handle keyboard shortcuts.

For instance, the tab key lets us move to different form fields. Enter is for submitting data, etc.

Use Events Over Callbacks

Emitting events from child to parent is better than callback functions that are passed in from parent to child.

For instance, we have to pass callbacks as props the following way:

index.js :

Vue.component("foo", {  
  props: ["showAlert"],  
  methods: {  
    displayAlert() {  
      if (typeof this.showAlert === "function") {  
        this.showAlert("foo");  
      }  
    }  
  },  
  template: `    
    <button @click='displayAlert'>Click Me</button>  
  `  
});

new Vue({  
  el: "#app",  
  methods: {  
    showAlert(text) {  
      alert(text);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <title>App</title>  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <foo :show-alert="showAlert"></foo>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we have the show-alert prop, which we pass the showAlert method from the root instance to the child. This is more complex and error-prone because we have to make sure that we passed in a function as the value of the prop.

We have to check that by using typeof of Vue’s built-in prop type validation.

Then we have to call the function that’s passed in as the value of the prop as we did in the displayAlert function. The name is different so it won’t clash with the showAlert prop.

On the other hand, if we emit events, then we won’t have to pass functions from parent to child to run something in the parent when something happens in the child.

For example, we can rewrite the example above by writing:

index.js :

Vue.component("foo", {  
  template: `    
    <button @click='$emit("button-clicked", "foo")'>Click Me</button>  
  `  
});

new Vue({  
  el: "#app",  
  methods: {  
    showAlert(text) {  
      alert(text);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <title>App</title>  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <foo @button-clicked="showAlert($event)"></foo>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

The code above is a lot simpler. We just call $emit with the event name as the first argument and the payload that we want to send to the parent as the second.

Then we can listen to the button-clicked event from the parent as we did in index.html by writing:

@button-clicked="showAlert($event)"

Then $event object has the payload, which is 'foo’, so we can pass it straight into the showAlert method. Finally, we’ll see the alert display when we click the button.

Limit In-Component Styles

Scoped in-component styles in single-file components are only applied to the component itself. If we’re reusing it in many locations or apps, then we should let the styles be in that app instead so that we won’t have conflicts of styles between our component and the styles that’s already in the app.

This makes styling reusable components hard since we’ve to deal with conflicts.

Therefore, we should either leave the styles out of the single-file component or have the ability to toggle them on and off.

For instance, we can toggle the styles with an is-styled prop as follows:

HelloWorld.vue :

<template>  
  <div>  
    <p :class="{'is-styled': isStyled}">{{ msg }}</p>  
  </div>  
</template>

<script>  
export default {  
  name: "HelloWorld",  
  props: {  
    msg: String,  
    isStyled: Boolean  
  }  
};  
</script>

<style scoped>  
.is-styled {  
  color: #42b983;  
}  
</style>

App.vue :

<template>  
  <div id="app">  
    <button @click="isStyled = !isStyled">Toggle Style</button>  
    <HelloWorld msg="Hello Vue" :is-styled="isStyled"/>  
  </div>  
</template>

<script>  
import HelloWorld from "./components/HelloWorld";

export default {  
  name: "App",  
  components: {  
    HelloWorld  
  },  
  data() {  
    return {  
      isStyled: true  
    };  
  }  
};  
</script>

In the code above, we have :class to bind the class dynamically according to the value of the isStyled prop that we passed in in HelloWorld.vue

Then in App.vue , we can set the isStyled value and pass it into the is-styled prop as the value so that we can have the ability to turn our HelloWorld ‘s component’s styles on and off as we wish.

Conclusion

We can use v-bind='$attrs' to inherit attributes from parent to child. If we’re going to add keyboard shortcuts handling to our app, we should following the conventions of other apps to make using our app convenient.

Also, we should emit events instead of calling callbacks passed from parent to child.

Finally, if we have shared components, we should either leave out the styles or have the ability to toggle them on and off.

Categories
JavaScript Vue

More Vue Data Grid Components that are Easy to Use

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at some Vue data grid libraries so we can avoid creating them from scratch ourselves.

vue-floatThead

vue-floatThead is a library that lets us create tables with a few options.

We can install it as follows:

npm install vue-floatthead

Then we can use it as follows:

main.js :

import Vue from "vue";  
import App from "./App.vue";  
import FloatThead from "vue-floatthead";  
Vue.use(FloatThead);  
Vue.config.productionTip = false;new Vue({  
  render: h => h(App)  
}).$mount("#app");

App.vue :

<template>  
  <div id="app">  
    <float-thead-table>  
      <thead>  
        <tr>  
          <th>  
            <a href="#">First Name</a>  
          </th>  
          <th>  
            <a href="#">Last Name</a>  
          </th>  
        </tr>  
      </thead>  
      <tbody>  
        <tr v-for='p of persons' :key='p'>  
          <td>{{p.firstName}}</td>  
          <td>{{p.lastName}}</td>           
        </tr>  
      </tbody>  
    </float-thead-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      persons: [  
        { firstName: "Jane", lastName: "Smith" },  
        { firstName: "Alex", lastName: "Smith" }  
      ]  
    };  
  }  
};  
</script>

We registered the component in main.js , then we use the float-thead-table component to build the table.

vue-good-table

vue-good-table is a table library with lots of options. It’s also easy to make a table with filtering and sorting with it.

To install it, we run:

npm install --save vue-good-table

Then to use it, we write:

main.js :

import Vue from "vue";  
import App from "./App.vue";  
import VueGoodTablePlugin from "vue-good-table";  
import "vue-good-table/dist/vue-good-table.css";

Vue.use(VueGoodTablePlugin);  
Vue.config.productionTip = false;

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

App.vue :

<template>  
  <div id="app">  
    <input type="text" v-model="searchTerm">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
    ></vue-good-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true  
        }  
      ],  
      rows: [{ name: "Jane" }, { name: "Alex" }]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

We registered the component with Vue.use and imported the styles, then we created the rows and columns data which are passed straight into the vue-good-table as props.

Also, we added the search-options prop to let us pass in the value of the input as the search value. It’s smart enough to search all columns without adding additional code.

Adding pagination is also very easy. To do this, we write:

<template>  
  <div id="app">  
    <input type="text" v-model="searchTerm">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
      :pagination-options="{  
        enabled: true,  
        mode: 'records',  
        perPage: 5,  
        position: 'top',  
        perPageDropdown: [3, 7, 9],  
        dropdownAllowAll: false,  
        setCurrentPage: 2,  
        nextLabel: 'next',  
        prevLabel: 'prev',  
        rowsPerPageLabel: 'Rows per page',  
        ofLabel: 'of',  
        pageLabel: 'page',   
        allLabel: 'All',  
      }"  
    ></vue-good-table>  
  </div>  
</template><script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true  
        }  
      ],  
      rows: [  
        { name: "Jane" },  
        { name: "Alex" },  
        { name: "James" },  
        { name: "Joe" },  
        { name: "Bob" },  
        { name: "Mary" }  
      ]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

All we did is pass some pagination options into the pagination-options props. The object we set as the value of the prop includes options for labels, text for the next and previous page buttons, the drop-down for the number of items to display on the table at one time, and more.

It also has a per-column filter feature which we can add easily by changing the column options as follows:

<template>  
  <div id="app">  
    <vue-good-table  
      :columns="columns"  
      :rows="rows"  
      :search-options="{  
        enabled: true,  
        externalQuery: searchTerm  
      }"  
    ></vue-good-table>  
  </div>  
</template>

<script>  
export default {  
  name: "App",  
  data() {  
    return {  
      searchTerm: "",  
      columns: [  
        {  
          label: "Name",  
          field: "name",  
          filterable: true,  
          filterOptions: {  
            enabled: true,  
            placeholder: "Filter Name",  
            filterValue: "",  
            filterDropdownItems: [],  
            filterFn: this.columnFilterFn,  
            trigger: "enter"  
          }  
        }  
      \],  
      rows: \[  
        { name: "Jane" },  
        { name: "Alex" },  
        { name: "James" },  
        { name: "Joe" },  
        { name: "Bob" },  
        { name: "Mary" }  
      ]  
    };  
  },  
  methods: {  
    search() {}  
  }  
};  
</script>

All we added was the follow property to the column entry:

filterOptions: {  
  enabled: true,  
  placeholder: "Filter Name",  
  filterValue: "",  
  filterDropdownItems: [],  
  filterFn: this.columnFilterFn,  
  trigger: "enter"  
}

to enable filtering for the column.

Conclusion

vue-floatThead is a basic table component to let us build a table. On the other hand, vue-good-table is a full-featured table component that has sorting, filtering, pagination right out of the box. It’s also very easy to add those features to our tables.

Categories
JavaScript Vue

Introduction to Vue.js Routing

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In order to create a single-page app with Vue.js, we have to map URLs to components so that when users go to a URL, it’ll show the corresponding component.

In this article, we’ll look at how to create some simple routes with the Vue Router.

Getting Started

We can use by Vue Router by adding a script tag with the URL for the Vue Router library.

We can make a simple app as follows:

src/index.js :

const Foo = { template: "<div>foo</div>" };  
const Bar = { template: "<div>bar</div>" };

const routes = [  
  { path: "/foo", component: Foo },  
  { path: "/bar", component: Bar }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="/foo">Foo</router-link>  
        <router-link to="/bar">Bar</router-link>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we defined 2 components Foo and Bar in src/index.js .

Then we mapped them to routes with:

const routes = [  
  { path: "/foo", component: Foo },  
  { path: "/bar", component: Bar }  
];

const router = new VueRouter({  
  routes  
});

Then we created a new Vue instance with:

new Vue({  
  el: "#app",  
  router  
});

In the template, we have router-links to map the routes to a tags with the URLs to correspond to the routes we define:

<router-link to="/foo">Foo</router-link>  
<router-link to="/bar">Bar</router-link>

Then we have router-view to show the components that are mapped to routes:

<router-view></router-view>

In the end, we should get:

Foo Link Bar Linkfoo

when we click on Foo Link .

and:

Foo Link Bar Linkbar

when we click on Bar Link .

Once we injected the router, we also get access to this.$router .

We can use it to navigate between routes. For example, we can write the following:

src/index.js :

const Foo = { template: "<div>foo</div>" };  
const Bar = { template: "<div>bar</div>" };

const routes = [  
  { path: "/foo", component: Foo },  
  { path: "/bar", component: Bar }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router,  
  methods: {  
    goBack() {  
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push("/");  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="/foo">Foo Link</router-link>  
        <router-link to="/bar">Bar Link</router-link>  
        <a href="#" @click="goBack">Go Back</a>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we click the Foo Link and Bar Link links a few times then click Go Back , we’ll see it’ll go back to the previous routes that we navigated to.

Route Parameters

We can get route parameters with the this.$route.params object.

For example, we can write an app that shows the URL parameter that’s passed in as follows:

src/index.js :

const User = {  
  computed: {  
    username() {  
      return this.$route.params.username;  
    }  
  },  
  template: `<div>{{username}}</div>`  
};

const routes = [{ path: "/user/:username", component: User }];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="/user/foo">Foo</router-link>  
        <router-link to="/user/bar">Bar</router-link>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The :username in “/user/:username” is the parameter, so we can get what passed in after /user/ by using this.$route.params.username .

We added a computed property username which returns this.$route.params.username so we can use:

`<div>{{username}}</div>`

to show the username URL parameter.

Conclusion

We can map URLs to components by using Vue Router.

Once we included it, we can define routes which map URLs to components. They can also take parameters, which can be retrieved with the this.$route object that’s made available by injecting the Vue router into our app.

To display links that link to Vue Router routes, we use router-link , and to display the components mapped to routes, we use router-view .

Categories
JavaScript Vue

Changing Scroll Behavior with Vue Router

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

Vue Router is a URL router that maps URLs to components.

In this article, we’ll look at how to change the scroll behavior of Vue Router routes.

Changing Scroll Behavior

Sometimes we may want to scroll to top when navigating to a new route or preserve the scrolling position of history entities like a real page reload.

Vue Router lets us adjust the scrolling behavior the way we like when route loads.

This only works if the browser supports history.pushState .

We can adjust scrolling behavior by providing a scrollBehavior function.

It has a to and from route objects as the first 2 parameters. The third argument is savePosition , is only available if this is a popstate navigation triggered by the browser’s back or forward buttons.

The function can return a scroll position object in the form of:

{ x: number, y: number }

or:

{ selector: string, offset? : { x: number, y: number }}

offset is supported since Vue Router 2.6.0

For example, we can add scrollBehavior to our routes as follows:

src/index.js:

const Foo = {  
  template: `  
    <div>  
      <div v-for='n in 100'>{{n}} foo</div>  
    </div>  
  `  
};  
const Bar = {  
  template: `  
  <div>  
    <div v-for='n in 100'>{{n}} bar</div>  
  </div>  
  `  
};

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes,  
  scrollBehavior(to, from, savedPosition) {  
    return { x: 0, y: 0 };  
  }  
});new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
      <router-link to="foo">Foo</router-link>  
      <router-link to="bar">Bar</router-link>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have:

scrollBehavior(to, from, savedPosition) {  
  return { x: 0, y: 0 };  
}

to scroll the next page back to the top when we navigate. Therefore, when we click on the links at the bottom of the page, we’ll go back to the top.

If we return something falsy or an empty object, no scrolling will happen.

If we change scrollBehavior to:

scrollBehavior(to, from, savedPosition) {  
  if (savedPosition) {  
    return savedPosition;  
  } else {  
    return { x: 0, y: 0 };  
  }  
}

Then we keep the scroll position of the page when we navigate back and forth with the forward and back buttons.

We can create the scroll to anchor behavior by setting the ID on our elements and then changing scrollBehavior as follows:

src/index.js :

const Foo = {  
  template: `  
    <div>  
      <div v-for='n in 100' :id='n'>{{n}} foo</div>  
    </div>  
  `  
};

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  }  
];

const router = new VueRouter({  
  routes,  
  scrollBehavior(to, from, savedPosition) {  
    if (to.hash) {  
      return {  
        selector: to.hash  
      };  
    }  
  }  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we go to /#/foo#100 we scroll to the bottom, then when we go to /#/foo#20 , we see 20 foo at the top of the screen.

Async Scrolling

We can also to async scrolling with scrollBehavior since Vue Router 2.8.0 by returning a promise that resolves to the same objects as synchronous scrolling.

For example, we can change the example above to:

src/index.js :

const Foo = {  
  template: `  
    <div>  
      <div v-for='n in 100' :id='n'>{{n}} foo</div>  
    </div>  
  `  
};

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  }  
];

const router = new VueRouter({  
  routes,  
  scrollBehavior(to, from, savedPosition) {  
    if (to.hash) {  
      return new Promise((resolve, reject) => {  
        setTimeout(() => {  
          resolve({  
            selector: to.hash  
          });  
        }, 1000);  
      });  
    }  
  }  
});

new Vue({  
  el: "#app",  
  router  
});

Then when we go to /#/foo#100 in our browser, we scroll to the bottom of the page after a second.

Conclusion

Scrolling behavior during route navigation can be changed by adding a scrollBehavior function to our router object. It takes the to and from parameters which are route objects, and a 3rd savedPosition parameter with the saved scroll position of the navigated route.

Scrolling behavior can be synchronous or asynchronous since Vue Router 2.8.0.

We can scroll to an element with the CSS selector or position.

Categories
Vue

Dynamic Route Matching with Vue Router

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to match routes dynamically with Vue Router.

Route Parameters

We can get route parameters with the this.$route.params object.

For example, we can write an app that shows the URL parameter that’s passed in as follows:

src/index.js :

const User = {
  computed: {
    username() {
      return this.$route.params.username;
    }
  },
  template: `<div>{{username}}</div>`
};

const routes = [{ path: "/user/:username", component: User }];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/user/foo">Foo</router-link>
        <router-link to="/user/bar">Bar</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

The :username in “/user/:username” is the parameter, so we can get what passed in after /user/ by using this.$route.params.username .

We added a computed property username which returns this.$route.params.username so we can use:

`<div>{{username}}</div>`

to show the username URL parameter.

We can also have multiple parameters in one route.

For example, we can write the following:

src/index.js :

const Name = {
  template: `<div>
    {{$route.params.firstName}}
    {{$route.params.lastName}}
  </div>`
};

const routes = [{ path: "/name/:firstName/:lastName", component: Name }];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/name/Jane/Doe">Jane</router-link>
        <router-link to="/name/Mary/Smith">Mary</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then when we click on the links, we get the first name and last name that we passed into the URL parameters.

:firstName and :lastName are matched to the params by position.

Reacting to Params Changes

We can watch the $route object to watch for param changes. Routes that the same name but different params use the same components. They won’t be re-rendered from scratch, so the lifecycle hooks won’t be called.

For example, we can write the following:

src/index.js :

const Name = {
  data() {
    return {
      oldName: "",
      newName: ""
    };
  },
  watch: {
    $route(to, from) {
      this.oldName = from.params.name;
      this.newName = to.params.name;
    }
  },
  template: `<div>
    Old: {{oldName}}
    New: {{newName}}
  </div>`
};

const routes = [{ path: "/name/:name", component: Name }];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/name/Jane">Jane</router-link>
        <router-link to="/name/Mary">Mary</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

In the code above, we have the Name component that’s mapped to a route that takes the name route parameter.

Also, Name has watcher for the $route object that takes the to and from parameters. They are the previous and current routes respectively.

So when we click back and forth between links, we’ll see the old parameter and new parameter displayed.

Catch all / 404 Not found Route

We can add * as a wildcard character for routes.

For example, we can use:

path: '*'

to match all routes and:

path: '/user-*'

to match anything that begins with user- .

For example, we can use the wildcard character as follows:

src/index.js :

const Foo = { template: "<p>foo</p>" };
const Bar = { template: "<p>bar</p>" };
const NotFound = { template: "<p>not found</p>" };
const routes = [
  { path: "/foo", component: Foo },
  { path: "/bar", component: Bar },
  { path: "*", component: NotFound }
];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/foo">Foo</router-link>
        <router-link to="/bar">Bar</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

When we go to any URL other than /foo or /bar , we’ll see the ‘not found’ message.

We can use the wildcard character with other text as follows:

src/index.js :

const Foo = { template: "<p>foo</p>" };
const Bar = { template: "<p>bar</p>" };
const routes = [
  { path: "/foo*", component: Foo },
  { path: "/bar", component: Bar }
];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/foo">Foo</router-link>
        <router-link to="/bar">Bar</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then we see foo when we go to any URL that starts with foo .

Regular Expressions

We can use regular expressions to match route parameters. For example, we can write:

src/index.js :

const Foo = { template: "<p>foo {{$route.params.id}}</p>" };
const Bar = { template: "<p>bar</p>" };
const routes = [
  { path: "/foo/:id(d+)", component: Foo },
  { path: "/bar", component: Bar }
];

const router = new VueRouter({
  routes
});

new Vue({
  el: "#app",
  router
});

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      <div>
        <router-link to="/foo">Foo</router-link>
        <router-link to="/bar">Bar</router-link>
      </div>
      <router-view></router-view>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>

Then when we go to /foo/1 we see foo 1 . If what comes after /foo/ isn’t a number, then we won’t see anything.

Conclusion

We can pass in route parameters by prefix whatever we want to pass in with a colon, then we can get it from the this.$route.params object.

The asterisk is a wildcard character that matches any URLs that don’t match the routes listed. We can also combine it with other text to match patterns that we want to match.

Finally, we can use regex to match route parameters.