Category Archives: Vue

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.

Minimal Vue and beyond

Vue gives us the ability to include it in a a minimal way by adding a simple script dependency (or installing it into your project’s node_modules using yarn add vue). Vue also comes with a CLI (vue-cli) for building application from a scaffolding application.

Let’s start at the simplest level and create a basic HTML page (no bundling, no built-in web server, nothing) and start writing Vue code. Create an index.html file

<!DOCTYPE html>
<head>
  <!-- development version -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <!-- production version
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  -->
</head>
<html>
  <body>
  </body>
</html>

The development version of Vue comes with console warnings etc. whereas the production version is optimized.

Let’s now place the following into the body tag

<div id="app">
  <button v-on:click="clicked">{{ message }}</button>    
  <div>{{ count }}</div>
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World',
    count: 0
  },
  methods: {
    clicked: function(event) {
      this.count++
    }
  }
})
</script>

What we’ve done is create the root (app) div, which corresponds to the el within the Vue options. Hence that Vue object is bound to the app element. It includes data in the form custom data, in this case a message (the usual Hello World example) but also a counter in the form of the count variable. The Vue options also include methods, in this case one labelled clicked is used in the button within the HTML.

Notice this use of this. to access the count in the method.

Now, in the HTML we use v- prefixed attributes to bind the elements to our Vue object (data and methods). So the button is bound to the v-on:click which in turn is assigned the method clicked as created in the Vue options.

Notice also the usage of the {{ }} (Mustache syntax) to allow us to inject (in this case) Vue data into the HTML.

As stated, there’s no web server or the likes, so we can now just drop this index.html into our chosen webserver and serve up Vue enabled web pages.

Taking it to the next step

In the previous example we use the Vue script from a CDN, but we can also run

yarn add vue

To include vue within the node_nodules of an application/website. Obviously this would be the route taken for anything more than the trivial example (above).

We’re not going to do anything more with this simple approach for building a Vue applications, however it does demonstrate that you can build a Vue application from scratch, choosing our preferred bundler etc. ourselves if required.

vue-cli

Let’s turn our attention now to creating a Vue application via the vue-cli tool.

So we’ve seen a minimal Vue page and we’ve seen we can bring Vue into our application in a way that allows us to pick and choose our technologies. With vue-cli we instead generate an application with all the “standard” pieces (i.e. bundler, webserver etc.).

Start by installing the vue-cli using

yarn global add @vue/cli

To check all went well, just run

vue --version

To create a project we simply run

vue create my-project

Obviously replacing my-project with your project name.

You will now be prompted to answer a couple of questions, for example

  • Please pick a preset
  • Pick the package manager to use when installing dependencies

See https://cli.vuejs.org/guide/creating-a-project.html#vue-create for a far more complete look at this stage.

If you simply choose the defaults you get bable, eslint and yarn configurations which is not actually what I wanted for this project.

So for the first prompt (Please pick a preset), I selected Manually select features and selected TypeScript, Router, Linter and Unit Testing, I then end up with further prompts asking whether I want class style components etc.

You’ll get the idea, vue-cli gives you default options all along the way.

Note: You can have vue-cli save your presets within ~/.vuerc or on Windows %USERPROFILE%/.vuerc, the option to save the presets is at the end of the available options for configuring your project.

If you prefer a UI to configure things with, then vue also comes with vue ui which will run a webapp (by default on port 8000). I’ll leave the reader to investigate the options themselves.

Once you’re happy with your configurations and you’ve generated your application, cd into your new project folder (cd my-project in case) and then run

yarn serve

This will start-up a server (by default on port 8080).

If we take a look at the code generated, you’ll notice we’ve moved far beyond the minimal use of Vue. I won’t cover too much here as really the topics around the generated code requires a post of their own, but suffice to say I’ve added a router (via the configuration selector). Vue creates main.ts which basically starts everything and mounts #app, which is within the new file type App.vue. The .vue files, I suppose are a little analogous to React’s JSX files in that they contain code and HTML, although obviously somewhat differently to JSX.

I tend to think of React as code with HTML/tags embedded in it (or returned from it) whereas Vue is more like markup with code embedded within it (similar to JSP, ASP etc. in that respect).

So just quickly looking at the generated Home.vue file (as stated, we’ll cover these more in another post). We have the following

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue';

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

This is pretty easy to understand, like ASP.NET of old, we’re creating templates for our HTML which may also contain Vue code (as per our original minimal index.html). So the template can be thought of as our HTML component, then the script contains the code associated with that template (ofcourse you might simply have a template if no code is required). In this script we’re really just hosting the HelloWorld.vue component, passing props to it in the form of the msg=”Welcome to Your Vue.js App”.

Note: There are different ways to create components, we’ll look at in other posts, for now we’ll simply assume the above is the usual layout of our Vue components.

Vue with Visual Code

I tend to use Visual Code for most of my web development, for Vue it’s worth installing the Vetur plugin which gives Vue tooling for VS Code. This includes syntax highlighting, auto-complete, linting etc.

Note: The vue-cli also included a script to run linting across your code if you want to run that in a shell.