Vue components

In a previous post we looked at creating a Vue application. Let’s now look a little more in depth by looking at creating Vue components.

Note: I will be using TypeScript and classes for this, so called “Class-Style component”.

A Vue component would be stored within a .vue file, hence MyComponent.vue for example. Vue components take the form of a template which is made up of HTML with embedded Vue values etc. Styles may also be defined within a style element which will hold standard CSS). Next up we’d have a script tag if our component does anything more than just being a template with or without styles.

Hence we might layout our component like this

<template>
  <div class="hello">
    <h1>{{ greeting }} World</h1>
  </div>
</template>

<style scoped>
h1 {
  color: red;
}
</style>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class MyComponent extends Vue {
  private greeting: string = 'Hello';
}
</script>

What we’ve done is create a template for our HTML which is ultimately a div with an h1 element with the text Hello World being displayed. Obviously the greeting part is supplied by the component as it’s wrapped in the {{ }} (Mustache) syntax.

Next we’ve got the style (these sections need not be in any specific order). We obviously don’t need a style nor script if no style or logic is required. However to demonstrate it’s usage we’ve got it here and style scoped to the component (i.e. not global). Ofcourse this will display our template text in H1 font and red text colour.

Now to the slightly more interesting bit. The script contains our code. First off we import the Component decorator and the Vue base class in the standard way.

Obviously as Vue uses the @Component decorators you’ll need the experimental features of TypeScript enabled, which is what the vue client did when creating our application.

As is pretty obvious, we derive our component from Vue and then implement data and methods. In this case we simply have a constant string with our greeting, before we make this editable, let’s look at how we render/use this component.

In our App.vue for example, we add the following to the app template, i.e.

<template>
  <div id="app">
      <MyComponent />
  </div>
</template>

The next bit is dependent upon whether you’re using a router or not. We need to register our component, so without a router our App.vue would contain the following script tag

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import MyComponent from './components/MyComponent.vue';

@Component({
  components: {
    MyComponent,
  },
})
export default class App extends Vue {}
</script>

If we’re using a router we probably be using views and hence would declare the following with the view (here’s an example view)

<template>
  <div class="home">
    <MyComponent />
  </div>
</template>

<script>
import MyComponent from '@/components/MyComponent.vue';

export default {
  name: 'home',
  components: {
    MyComponent,
  },
};
</script>

Adding properties

Now we’ve seen how to create a component we’ll want to extend it by adding properties (attributes in HTML terms). So for example, instead of fixing our greeting string to “Hello” we’ll let the user of our component set the greeting.

To do this we need to add the Prop decorator to the greeting string with MyComponent, i.e.

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';

@Component
export default class MyComponent extends Vue {
  @Prop() private greeting!: string;
}
</script>

and now from the code using MyComponent we would write

<MyComponent greeting="Hello" />

Adding methods/handlers

Let’s extend our component with a button which, when clicked, increments a counter. So our component script now looks like this

import { Component, Vue, Prop } from 'vue-property-decorator';

@Component
export default class MyComponent extends Vue {
  private count: number = 0;

  @Prop() private greeting: string = 'Hello';

  handleClick(): void {
    this.count = this.count + 1;
  }
}

Now our template is changed to this

<template>
  <div class="hello">
    <h1>{{ greeting }} World</h1>
    <button @click="handleClick">Click</button>
    <h1>{{ count }}</h1>
  </div>
</template>

Note: We can use the @click or v-on:click – the @ is just a shorthand for v-on: in this instance.