Vue Fundamentals

I think of building web apps as putting LEGOs together.

Components

Components are the building blocks in Vue.

We create them by combining HTML , CSS , & JS .

Template

A component must contain an opening & closing template tag & template tags contain HTML .

./component.vue
vue
<template> <h1>Wizards</h1> !!!!! </template>

Templates contain 1 root tag(best practice).

./component.vue
vue
<template> <div> <h1>Wizards</h1> <ul> <li>Harry</li> <li>Ron</li> <li>Hermione</li> </ul> </div> </template>

Both standard & semantic HTML tags are available.

./component.vue
vue
<template> <div> <h1>Wizards</h1> <ul> <li><b>Harry</b></li> <li><i>Ron</i></li> <li><strong>Hermione</strong></li> </ul> <input /> </div> </template>

Standard HTML attributes such as style, class, autofocus, etc... apply.

./component.vue
vue
<template> <div> <h1 style="color: red">Wizards</h1> <ul> <li> <b style="font-size: 100px"> Harry </b> </li> <li><i>Ron</i></li> <li><strong>Hermione</strong></li> </ul> <input autofocus /> </div> </template>

Use none, one or many attributes is the technique used to create dynamic components.

Consider how adding this type attribute & value changes the behavior of the input tag for example.

./component.vue
vue
<template> <div> <h1 :style="{'color': 'red'}">Wizards</h1> <ul> <li> <b style="font-size: 100px"> Harry </b> </li> <li><i>Ron</i></li> <li><strong>Hermione</strong></li> </ul> <input autofocus type="number" /> !!!!! </div> </template>

Style

Separate HTML from CSS when possible.

Use a style tag to extract CSS.

Placing CSS there helps when components grow & makes template easier to reason about.

./component.vue
vue
<template> <div> <h1>Wizards</h1> <ul> <li>Harry</li> <li>Ron</li> <li>Hermione</li> </ul> <input autofocus /> </div> </template> <style> h1 { color: red; } b { font-size: 30px; } </style>

Script

The script tag is where we write JS code.

We can define variables there for example, in this case wizard .

./component.vue
vue
<script setup> const wizard = 'Programmer' </script> <template> <!-- html... --> </template> <style> /* css... */ </style>

JS defined in the script tag can be used in the template using handlebars/mustaches.

./component.vue
vue
<script setup> const wizard = 'Programmer' </script> <template> <div> <h1>Wizards</h1> <ul> <li>Harry</li> <li>Ron</li> <li>Hermione</li> <li>{{ wizard }}</li> </ul> <input autofocus /> </div> </template> <style> h1 { color: red; } b { font-size: 30px; } </style>

Directives

JS is also used to programmatically render HTML with the help of directives.

A simple directive is v-if .

It evaluates a JS statement and renders the HTML if the JS expression returns true .

./component.vue
vue
<script setup> const expression = 1 === 1 </script> <template> <div v-if="expression"> True </div> </template>

Like all if conditionals else statements can be added.

It's v-else in Vue.

./component.vue
vue
<script setup> const expression = 1 === 'one' </script> <template> <div v-if="expression"> False </div> <div v-else> True </div> </template>

And with the v-else-if an infinite number of possibilities results are possible.

./component.vue
vue
<script setup> const value = 1 </script> <template> <div v-if="value === '1'"> False </div> <div v-else-if="value === 'One'"> False </div> <div v-else-if="value === 'Uno'"> False </div> <div v-else-if="value === 'Un'"> False </div> <!-- how many more ways might we be wrong...? 🤔 --> </template>

There are many directives.

They all start with ' v- '.

  • v-if
  • v-else-if
  • v-else
  • v-for
  • v-html
  • v-text
  • etc...

Interpolation

Separate JS from HTML when possible.

Doing so makes your code easier to understand.

To do so define a script which will hold your JS.

./component.vue
vue
<script setup> </script> <template> <div> </div> </template>

Now define the variables you want to use in your templates.

./component.vue
vue
<script setup> const pronoun = 'Harry' </script> <template> </template>

Now you can interpolate the vars into the template with mustache/handlebar syntax.

./component.vue
vue
<script setup> const pronoun = 'Harry' </script> <template> <div> {{ pronoun }} </div> </template>

You can create something magical by using multiples vars.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' </script> <template> <div> {{ pronoun }} {{ verb }} {{ adjective }} </div> </template>

Combing lists & loops in a v-for creates enchanting possibilities.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' const spells = ['HTML', 'JS', 'Vue'] </script> <template> <div> {{ pronoun }} {{ verb }} {{ adjective }} </div> <ul> <li v-for="spell of spells" > <div>{{ spell }}</div> </li> </ul> </template>

Especially if you combine new skills with previous abilities like the v-if directive.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' const spells = ['HTML', 'JS', 'Vue'] </script> <template> <div> {{ pronoun }} {{ verb }} {{ adjective }} </div> <ul> <li v-for="spell of spells" > <div v-if="spell === 'Vue'" style="color: green">{{ spell }}</div> <div v-else>{{ spell }}</div> </li> </ul> </template>

Add a ternary operator to simplify the your code a bit.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' const spells = ['HTML', 'JS', 'Vue'] </script> <template> <div> {{ pronoun }} {{ verb }} {{ adjective }} </div> <ul> <li v-for="spell of spells" > <div :style="{color: spell === 'Vue' ? 'green' : 'black'}">{{ spell }}</div> </li> </ul> </template>

We could have concatenated our vars earlier as well.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' const spells = ['HTML', 'JS', 'Vue'] </script> <template> <div> {{ pronoun + verb + adjective }} </div> <ul> <li v-for="spell of spells" > <div :style="{color: spell === 'Vue' ? 'green' : 'black'}">{{ spell }}</div> </li> </ul> </template>

And lastly, we can define functions in scripts and invoke them in the templates.

./component.vue
vue
<script setup> const pronoun = 'Harry' const verb = ' is ' const adjective = 'magical' const spells = ['HTML', 'JS', 'Vue'] function hotSpell(spell) { return spell === 'Vue' ? 'green' : 'black' } </script> <template> <div> {{ pronoun + verb + adjective }} </div> <ul> <li v-for="spell of spells" > <div :style="{color: hotSpell(spell)}">{{ spell }}</div> </li> </ul> </template>

Combining HTML, JS, directives, handlebars & loops allows

Binding

As data changes UI should as well.

But to make the UI reflect changes to data in real time we have to use binding.

For example, here we define num and increment it every second with an an interval.

We expect the update to num every second to update the UI.

./component.vue
vue
<script> let num = 0 setInterval(() => { num += 1 }, 1000) </script> <template> <div :class="{ 'text-green-400': (num % 2) == 0, }" > Color {{ num }} </div> </template>

Yet the UI doesn't update every second like you'd think.

However if you log num in the interval and inspecting it in the dev tools you'll see it updates.

Preview

The issue can be solved by binding num with ref() provided by Vue.

First you have to update the way you define num .

When defining num invoke ref() with it's initial value, 0 , and set that to num

./component.vue
vue
<script> let num = 0 // [!code --] let num = ref(0) // [!code ++] setInterval(() => { num += 1 }, 1000) </script> <template> <div :class="{ 'text-green-400': (num % 2) == 0, }" > Color {{ num }} </div> </template>

Then change the update syntax by adding a .value

./component.vue
vue
<script> let num = ref(0) setInterval(() => { num += 1 // [!code --] num.value += 1 // [!code ++] }, 1000) </script> <template> <div :class="{ 'text-green-400': (num % 2) == 0, }" > Color {{ num }} </div> </template>

Now you'll see that the UI updates in real time as you expect.

  • Initialize vars with ref() .
    • const value = ref(0)
  • Reference and update the .value property of vars you've bound.
    • num.value += 1
  • In templates vars do not require .value .
    • Color {{ num }}
    • 'text-green-400': (num % 2) == 0,

Learn how to organize components in your projects next.