Vue.js Certification

Bootcamp

πŸ‘‹

Welcome!

Let us introduce ourselves

800+ Video Lessons

150,000 users

Alex Kyriakidis

Daniel Kelly

Debbie O'Brien

Chris Fritz

Maria Lamardo

Roman Kuba

SΓ©bastien Chopin

Filip Rakowski

Mostafa Said

Rolf Haug

What is It?

  • hands-on and expert-guided exam prep
  • a 3 week program consisting of:
    • πŸ‘¨β€πŸ« live instruction
    • πŸ‘¨β€πŸ’» coding challenges
    • πŸ“š homework assignments
    • πŸ§ͺ practice exam

Our goal is for you to ace the exam πŸ’ͺ

What to expect?

Day 1 and Day 2 will look similar

Day 1

6 Sections

πŸ‘¨πŸΌβ€πŸ« presentation

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’» exercise

πŸ’¬ Q&A

πŸ“Ί solution

πŸ‘¨πŸΌβ€πŸ«

Presentation will look much like what we're doing now

πŸ’¬

Questions are taken from the chat.

Global Chat

  • Chat during the session
  • Communicate with everyone while you are in a room

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Exercises are your time to practice what you've learned

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’» Exercises

  • on your own machine
  • work in teams
  • exercises are independent
  • Β±20 minutes

(show structure in repo)

Global Chat

while in a room

  • Send 'Help Bees 🐝' if you need help from a trainer
  • Send 'Done Bees 🐝' if everyone in your team is done with the exercise
  • Use your team name instead of Bees
  • Emojis are optional

Global Chat

while in a room

  • Send 'Help Bees 🐝' if you need help from a trainer
  • Send 'Done Bees 🐝' if everyone in your team is done with the exercise
  • Use your team name instead of Bees
  • Emojis are optional

Day 1

  1. Intro to Vue
  2. Template Syntax
  3. Event Handling
  4. Reactivity Fundamentals
  5. Class and Style bindings
  6. Form Input Bindings

Section Topics

Day 2

  1. Component basics
  2. Lifecycle hooks
  3. Slots
  4. Watchers
  5. Template refs
  6. Transitions
  7. Plugins

Section Topics

What to expect?

Day 3 will be a little different

Day 3

We'll do a live practice exam together!

  • Real-time multiple-choice questions
    We'll explain and discuss the solutions
  • A feature coding challenge
    You complete yourself and we'll live-code the solution
  • A bug coding challenge
    You complete yourself and we'll live-code the solution

πŸ“š We'll send you home with another practice exam too!

Let's join rooms and meet each other!

⏰ 5 mins

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’» everybody join a room?

Day 1

Let's start learning the material for

🚦

Intro to Vue and

Reactivity Fundamentals

1

Section

What is Vue.js?

What is Vue.js?

Build Interactive UI Elements

Interactive Forms

Cookie Consent Dialogs

Carousels

Build Full Applications

  • Vue Components - UI Elements
  • Vue Router - Pages
  • Pinia - State Management
  • Combine with an API for Data

What about others?

React

Angular

Svelte

They are similar in use case just a little different in approach and syntax

What about others?

React

Angular

Svelte

What about others?

React

Angular

Svelte

  • Vue was created by an individual (Evan You), not a company
  • Vue is maintained by a community instead of a company
  • Vue is notoriously easy to learn

Who Uses Vue?

+ Many more

How to Get Started?

That depends on your needs

How to Get Started?

Vue is known as a progressive framework

We've Got Several Options

Depending on How You'd like to "Do" Vue

And what your site or apps needs are

Have an existing static or server-rendered site?

Option 1

Use Vue to enhance it with a direct link via a script tag

<script src="https://unpkg.com/vue@3"></script>

πŸ‘‡

Have an existing static or server-rendered site?

Use Vue to enhance it with a direct link via a script tag

<script src="https://unpkg.com/vue@3"></script>

πŸ‘‡

Have an existing static or server-rendered site?

βœ… No Build Step Required

Use Vue to enhance it with a direct link via a script tag

<script src="https://unpkg.com/vue@3"></script>

πŸ‘‡

Have an existing static or server-rendered site?

⛔️BUT can't use Single File Components (SFCs)

Want to create an SPA?

That runs entirely client side and handles all templating and logic with Vue and JavaScript

Option 2

Bootstrap a Vue app with Vite for a build tool

npm create vue@latest

πŸ‘‡

Want to create an SPA?

Want to create an SPA?

  • βœ… Great for admin dashboards, internal company tooling, etc
  • βœ… Great dev experience from Vite with HMR
  • βœ… Support for Single File Components and script setup
  • βœ… Optionally scaffold with popular tooling like Pinia, TypeScript, Vitest, ESLint, Vue Router, and More
  • ⛔️ Slightly harder to setup (but usually worth it)
  • ⛔️ Can't be used to enhance an existing site

Want to create a server rendered app?

That uses JavaScript and Vue for logic and templating on both the client and the server

Option 3

Use the meta-framework Nuxt

npx nuxi init

πŸ‘‡

Want to create a server rendered app?

Want to create a server rendered app?

  • βœ… Great for sites that require SEO
  • βœ… Great dev experience from Vite with HMR
  • βœ… Support for Single File Components and script setup
  • βœ… Tons of built-in conventions
  • βœ… Auto importing of all the things
  • βœ… File based routing
  • βœ… and more!
  • ⛔️ Can't be used to enhance an site
  • ⛔️ Universal apps can be tricky

Those are the 3 primary options

There's more but these are the most popular

From a CDN

SPA

SSR

Vue as an SPA

Bootcamp and the Exam Focuses on

Vue as an SPA

Bootcamp and the Exam Focuses on

  • βœ… We aren't concerned with SSR
  • βœ… Assumes SFC's unless otherwise stated
  • βœ… most concepts and syntaxes apply to all approaches
  • βœ… choosing to focus code examples on a single approach is less confusing

The Composition API

Bootcamp and the Exam Focuses on

Vue has 2 ways to write components:

βš™οΈ The options API

πŸ““ The composition API

βš™οΈ The options API

  • the original Vue component syntax
  • can be more structured and organizedΒ 

BUT

  • more flexible code organization
  • better logic reuse
  • better type inference (TS)
  • smaller production bundle and less overhead

instead of the Options API, the exam FOCUSES on the COMPOSITION API

❓FAQ❓

Can I use the options API during the exam?

❓FAQ❓

Can I use the options API during the exam?

Yes! Kind of...

❓FAQ❓

Can I use the options API during the exam?

βœ…

You can provide your coding challenge solutions in either API

⛔️

Multiple Choice Questions will use the Composition API

⛔️

Coding Challenge Boilerplate will use the Composition API

Script Setup Syntax

Bootcamp and the Exam Focuses on

Script Setup Syntax

Bootcamp and the Exam Focuses on

  • the way most people will work with the composition API
  • compile time syntactic sugar to reduce boilerplate code

Practical Implications

  • When there are options for how to "do" Vue focus on:
    • Single File Components
    • Composition API
    • Script Setup (vs setup method)
  • Do have a high level understanding of various other ways to "do" Vue

The Application Instance

Back to Creating a New App...

The Application Instance

Every Vue application starts by creating a new application instance

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

All Vue apps have a single top-level (root) component

main.js

The Application Instance

Every Vue application starts by creating a new application instance

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

This app only exists in "JavaScript Land"

main.js

The Application Instance

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.mount("#app")

We must mount it to a DOM element to render anything to the page

main.js

The Application Instance

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.errorHandler = (err) => {
  /* handle error */
}

app.mount("#app")

Use config object to set

some app level settings

main.js

App Config Options

[Application API Docs](vuejs.org/api/application.html)

  • errorHandler - global handler for uncaught errors

  • warnHandler - for runtime warnings from Vue

  • performance - enable component init, compile, render and patch performance tracing

  • and more - compilerOptions, globalProperties, optionMergeStrategies

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.mount("#app")

main.js

Let's look into the root level App component

The Application Instance

Single File Components









<style scoped>
.bg-blue{
  background: blue;
}
</style>

App.vue

SFC's encapsulate the component's logic (JavaScript), template (HTML), and styles (CSS) in a single file.

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>
<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>

Single File Components









<style scoped>
.bg-blue{
  background: blue;
}
</style>

App.vue

The order of each section is not important

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>
<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>

Single File Components









<style scoped>
.bg-blue{
  background: blue;
}
</style>

App.vue

The examples in the Vue.js docs do always start with the Script tag

(so this is a common convention but not required)

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>
<template>
  <div class="bg-blue">{{msg}}</div>
</template>

<style scoped>
.bg-blue{
  background: blue;
}
</style>

Single File Components

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

App.vue

An SFC doesn't have to contain ALL of the sections

(for those who use Tailwind CSS you'll often exclude the style tag)

Single File Components

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

App.vue

But it MUST contain at least a script OR a template

Not using these slides below

But keeping for record, just in case

Single File Components

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

App.vue

Components with ONLY a Script Tag are called

Renderless Components

Single File Components

<template>
  <div class="bg-blue">{{msg}}</div>
</template>

App.vue

Components with ONLY a template Tag are often (unofficially) calledΒ  Presentational Components

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div>{{msg}}</div>
</template>

App.vue

Single File Components

The setup attribute enables "script setup" mode which makes it easier to use the Composition API

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div>{{msg}}</div>
</template>

App.vue

Single File Components

What's happening in each section?

Declarative Rendering

  • We declare data in script
  • and use double curly braces to display it in the DOM
<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div>{{msg}}</div>
</template>

App.vue

Declarative Rendering

  • βœ… Better than Vanilla JS because we don't have to manually query the DOM and keep it in sync with the data
  • βœ… Better than HTML only because we can change what's in the DOM without totally refreshing the page
<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div>{{msg}}</div>
</template>

App.vue

⚑️Reactivity System

⚑️Reactivity System

App.vue

  • Reactive data is declared with the ref function
  • We'll talk more about declaring reactive data later
  • For now, know that ref is the officially recommended approach
<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <div>{{msg}}</div>
</template>

⚑️Reactivity System

Whenever the data updates the DOM re-renders the div

⚑️Reactivity System

A common way of updating data is by accepting user input with v-model

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <input v-model="msg">
  <div>{{msg}}</div>
</template>

⚑️Reactivity System

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <input v-model="msg">
  <div>{{msg}}</div>
</template>

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 1

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Template Syntax

2

Section

How do we interact with the data in the script section from the template?

How do we interact with the data in the script section from the template?

  1. With the mustache syntax
  2. With directives

Mustache Syntax

display text to the page

<div>{{msg}}</div>

Directives

Special HTML Attributes provided by Vue

Directives

Always start with a v-

<div>
  {{msg}}
  <input v-model="msg">
</div>

Directives

Apply reactive behavior to the DOM

v-bind allows us to bind Vue.js Data to any HTML attribute

Common Directives

Common Directives: v-bind

<script setup>
const path = ref("/path/to/cat.jpg");
const alt = ref("a smiling cat");
</script>

<template>
<div>
  <img v-bind:src="path" v-bind:alt="alt" />
</div>
</template>

The attribute is an argument to the v-bind directive

<div>
  <img src="/path/to/cat.jpg" alt="a smiling cat" />
</div>

Rendered Output

Common Directives: v-bind

<script setup>
const path = ref("/path/to/cat.jpg");
const alt = ref("a smiling cat");
</script>

<template>
<div>
  <img v-bind:src="path" v-bind:alt="alt" />
</div>
</template>

use square brackets to make dynamic

Dynamic Directive Arguments

<script setup>
import { ref } from "vue";
  
const path = ref("/path/to/cat.jpg");
const alt = ref("a smiling cat");
const dynamicAttr = ref("src")
</script>

<template>
<div>
  <img v-bind:[dynamicAttr]="path" v-bind:alt="alt" />
</div>
</template>

shorten v-bind to just a colon

V-bind shorthand :

<script setup>
import { ref } from "vue";
  
const path = ref("/path/to/cat.jpg");
const alt = ref("a smiling cat");
const dynamicAttr = ref("src")
</script>

<template>
<div>
  <img v-bind:[dynamicAttr]="path" :alt="alt" />
</div>
</template>

Conditional Rendering

Common Directives

v-if allows us to conditionally render elements

Common Directives: v-if

<script setup>
import {ref} from "vue";
const sunny = ref(true);
</script>

<template>
<div>
  <p v-if="sunny">
    It's sunny today! 🌞
  </p>
</div>
</template>

Common Directives

v-else and v-else-if

Common Directives: v-else

<script setup>
import {ref} from "vue";
const sunny = ref(false);
</script>

<template>
<div>
  <p v-if="sunny">It's sunny today! 🌞</p>

  <p v-else>Is it raining? β˜”οΈ</p>
</div>
</template>

Common Directives: v-else-if

<script setup>
import {ref} from "vue";
const sunny = ref(false);
const windy = ref(true);
</script>

<template>
  <p v-if="sunny">It's sunny today! 🌞</p>

  <p v-else-if="windy">It's windy today! 🌬</p>

  <p v-else>Is it raining? β˜”οΈ</p>
</template>

Conditional Display with v-show

Common Directives: v-show

<script setup>
import {ref} from "vue";
const sunny = ref(false);
</script>

<template>
  <p v-if="sunny">It's sunny today! 🌞</p>
  <p v-show="sunny">It's sunny today! 🌞</p>
</template>

Neither will display to the page

Common Directives: v-show

<script setup>
import {ref} from "vue";
const sunny = ref(false);
</script>

<template>

  <p style="display: none;">It's sunny today! 🌞</p>
</template>

Rendered Result

v-if leaves NO DOM element

v-show hides with style

πŸ€” Which Should I Use?

v-show or v-if

v-show or v-if

Use v-show if the element will be toggled often and/or quickly. This will be slightly more performant

Directives support inline expressions

Directives support inline expressions

<script setup>
import {ref} from "vue";
const weather = ref("hurricane");
</script>

<template>
<div>
  <p v-if="weather === 'sunny'">It's sunny today! 🌞</p>

  <p v-else-if="weather === 'windy'">It's windy today! 🌬</p>

  <p v-else>Is it raining? β˜”οΈ</p>
</div>
</template>	

Mustache Syntax also supports inline expressions

Mustache Syntax also supports inline expressions

<script setup>
import {ref} from "vue";
const ok = ref(true);
</script>

<template>
<div>
  Is everything ok? {{ ok ? "Yes" : "No" }}
</div>
</template>	

Don't bloat your template with inline expressions

Keep it simple or extract the logic

List Rendering with v-for

List Rendering with v-for

<script setup>
import {ref} from "vue";
const heroes = ref([
  {id: 1, name: 'Bruce Wayne', alterEgo: 'Batman'},
  {id: 2, name: 'Clark Kent', alterEgo: 'Superman'},
  {id: 3, name: 'Tony Stark', alterEgo: 'Ironman'},
  {id: 4, name: 'Diana Prince', alterEgo: 'Wonder Woman'}
])
</script>

List Rendering with v-for

Is the individual array item

Name of the reactive data

Can be any name

<script setup>
import {ref} from "vue";
const heroes = ref([
  {id: 1, name: 'Bruce Wayne', alterEgo: 'Batman'},
  {id: 2, name: 'Clark Kent', alterEgo: 'Superman'},
  {id: 3, name: 'Tony Stark', alterEgo: 'Ironman'},
  {id: 4, name: 'Diana Prince', alterEgo: 'Wonder Woman'}
])
</script>

<template>
<ul>
  <li v-for="hero in heroes"> {{ hero.name }} </li>  
</ul>
</template>

List Rendering with v-for

Can also access the index

  <li v-for="(hero, index) in heroes"> {{ hero.name }} </li>  

List Rendering with v-for

<ul>
  <li> Bruce Wayne </li>  
  <li> Clark Kent </li> 
  <li> Tony Stark </li>
  <li> Diana Prince </li>
</ul>

Rendered Output

<div v-for="hero in heroes">
  {{ hero.name }}
</div>

v-for scope

The item is available inside the element

<div v-for="hero in heroes">
  <span>{{ hero.name }}</span>
</div>

v-for scope

The item is available inside child elements

<img 
  v-for="image in myImages" 
  :src="image.src"
  :alt="image.title" />

v-for scope

The item is available on the element

<img 
  v-if="image.src"
  v-for="image in myImages" 
  :src="image.src"
  :alt="image.title" />

v-for scope

It is not recommended to use v-if with v-for on the same element

<img 
  v-for="image in filteredImages" 
  :src="image.src"
  :alt="image.title" />

v-for scope

<template v-for="image in myImages">
  <img 
    v-if="image.src"
    :src="image.src"
    :alt="image.title" />
</template>

OR

v-for :key

<li v-for="hero in heroes" :key="hero.id"> {{ hero.name }} </li>  
  • Uniquely identifies each item to make updates more efficient
  • Necessary in cases where array items will change order
  • It is recommended to provide a key attribute with v-for whenever possible
  • It should NOT be the index (but something that uniquely describes each item)

v-for is for MORE than arrays

v-for with Objects

<script setup>
import { ref } from 'vue';
const framework = ref({
  name: 'Vue',
  isAwesome: true,
  latestMajorVersion: 3,
});
</script>

<template>
  <ul>
    <li v-for="value in framework">{{ value }}</li>
  </ul>
</template>
  <ul>
    <li>Vue</li>
    <li>true</li>
    <li>3</li>
  </ul>

Rendered Output

v-for with Objects

<li v-for="(value, key) in framework">{{key}} {{value}}</li>

access property key

<li>name Vue</li>
<li>isAwesome true</li>
<li>latestMajorVersion 3</li>

Rendered Output

v-for with a Range

<li v-for="n in 3">{{n}}</li>
<li>1</li>
<li>2</li>
<li>3</li>

Rendered Output

v-for with a String

<li v-for="char in 'Hello'">{{char}}</li>
<li>H</li>
<li>e</li>
<li>l</li>
<li>l</li>
<li>o</li>

Rendered Output

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 2

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Coffee Break

β˜•οΈ

Event Handling

3

Section

Vue.js allows us to easily to attach event listeners in our HTML

v-on allows us to add event listeners to the DOM

<button v-on:click="raining = true">Make it rain!</button>

v-on syntax

Event

(inline handler)

Handler

<button @click="raining = true">Make it rain!</button>

v-on shorthand

shorten to @

v-on syntax

Function

<button @click="raining = true">Make it rain!</button>
makeItRain()

v-on syntax

<script setup>
import {ref} from "vue";
const raining = ref(false);

function makeItRain(){
  raining.value = true;  
}
</script>

<template>
<button @click="makeItRain()">Make it rain!</button>
</template>
<button v-on:click="raining = true">Make it rain!</button>
makeItRain()

Define a handler function in script setup

Notice .value

v-on syntax

<script setup>
import {ref} from "vue";
const raining = ref(false);

function makeItRain(){
  raining.value = true;  
}
</script>

<template>
<button @click="makeItRain">Make it rain!</button>
</template>

Can shorten handler by excluding the parens

v-on syntax

<script setup>
import {ref} from "vue";
const raining = ref(false);

function makeItRain(e){
  raining.value = true;  
}
</script>

<template>
<button @click="makeItRain">Make it rain!</button>
</template>

This automatically passes the event

in this case it's a browser native Event object

v-on syntax

The same event is available inline as $event

<script setup>
import {ref} from "vue";
const raining = ref(false);

function makeItRain(e){
  raining.value = true;  
}
</script>

<template>
<button @click="makeItRain($event)">Make it rain!</button>
</template>

We can also make listeners dynamic

Dynamic listeners

It's just a directive argument!

<script setup>
//...
const listener = ref("click");
</script>

<template>
<button v-on:[listener]="makeItRain">Make it rain!</button>
</template>

Dynamic listeners

<script setup>
//...
const listener = ref("click");
</script>

<template>
<button @[listener]="makeItRain">Make it rain!</button>
</template>

It works with the shorthand too

We can have as many listeners as we want

Multiple listeners

<script setup>
const handleClick = ()=> console.log("clicked");
const handleMouseEnter = ()=> console.log("mouse entered")
</script>

<template>
  <button 
	@click="handleClick" 
	@mouseenter="handleMouseEnter"
   >
      Make it rain!
  </button>
</template>

Or we can bind multiple listeners at one time

Multiple listeners at once

<script setup>
const listeners = {
  click: () => console.log('clicked'),
  mouseenter: () => console.log('mouse entered'),
};
</script>

<template>
  <button v-on="listeners">Make it rain!</button>
</template>

All listeners as object

Event Modifiers

Event Modifiers

A shortcut for altering how the browser reacts to certain events

Event Modifiers

<form @submit.prevent="submitForm">
  ...
</form>
submitForm(event) {
  event.preventDefault()
  // ...
}

By moving the modifier to the template we keep our methods clean

Let's try it together

Event Modifiers

πŸ’‘ TIP: Order Matters

// prevents click's default action on
// the element itself and its children
@click.prevent.self
// only prevent click's default action 
// on the element itself.
@click.self.prevent

Key Modifiers

Key Modifiers

Allows us to quickly attach listeners to specific keys

Key Modifiers Example

<textarea @keydown.esc="clearText" />
  • .enter
  • .tab
  • .delete
    (captures both "Delete" and "Backspace" keys)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

Key Aliases ​

  • .ctrl
  • .alt
  • .shift
  • .meta

System Modifier Keys

  • .a
  • .b
  • ....

Any Valid Key Name

Let's try it!

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 3

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Reactivity Fundamentals

4

Section

So far we've used

ref()

to define reactive data

You could also use

reactive()

What's the difference? πŸ€”

  • `reactive` creates a proxy that behaves like the original object
  • `ref` creates a wrapper that exposes the original value via .value

According to the docs:

Practically speaking what does that mean?

Ref Works on Primitives

Reactive does not

// βœ… ref works
const framwork = ref('Vue')
const isAwesome = ref(true)
const created = ref(2014)

// ❌ won't work 
const framwork = reactive('Vue') 
const isAwesome = reactive(true)
const created = reactive(2014)

Can Re-assign whole ref values but not reactive

// βœ… ref works
let posts = ref(['post 1', 'post 2'])
posts.value = ['post 3', 'post 4']
// ❌ won't work 
let posts = reactive(['post 1', 'post 2'])
posts = ['post 3', 'post 4']

Ref requires .value reactive does not

// ref
const framework = ref({
  name: 'Vue',
  author:'Evan You',
  tags: ['javascript', 'vue']
})
                       ⬇️
console.log(framework.value.name)
// reactive
const framework = reactive({
  name: 'Vue',
  author:'Evan You',
  tags: ['javascript', 'vue']
})

console.log(framework.name)

Can destructure object of refs, cannot destructure a reactive object

// βœ… ref works 
const framework = {
  name: ref('Vue'),
  author: ref('Evan You'),
  tags: ref(['javascript', 'vue'])
}

const { name } = framework
// ❌ reactive doesn't
const framework = reactive({
  name: 'Vue',
  author:'Evan You',
  tags: ['javascript', 'vue']
})

// name is no longer reactive
const { name } = framework

Can convert reactive object to refs

// βœ… will work
const framework = toRefs(reactive({
  name: 'Vue',
  author:'Evan You',
  tags: ['javascript', 'vue']
}))

const { name } = framework

Which to use? πŸ€”

  • Sometimes you have no choice
    • Must use refs for primitives
    • Must use ref when replacing whole value
  • Otherwise, it's personal preference
  • Many choose to use ref for everything
  • The Vue.js docs recommend ref

Ref or Reactive

Besides reactive state, we can also define derived reactive state with

computed()

<script setup>
import {ref} from "vue";

const message = ref("Hello world");
</script>
<template>
  <h1>{{ message.split('').reverse().join('') }}</h1>
  <input v-model="message">
</template>

We can do inline expressions

BUT this has drawbacks:

  • Makes the template messy
  • Makes values hard to re-use

Instead we can use computed

<script setup>
import { ref, computed } from "vue";

const message = ref("Hello world");
const backwardsMessages = computed(()=>{
  return message.value.split('').reverse().join('')
})
</script>
<template>
<h1>{{backwardsMessages}}</h1> 
<input v-model="message">
</template>

Some common use cases

Filtering Array Data

<script setup>
import { ref, computed } from 'vue';

const movies = ref([
  { title: 'Jurassic Park', rating: 8.2 },
  { title: 'The Shawshank Redemption', rating: 9.3 },
  { title: 'The Dark Knight', rating: 9.0 },
  { title: 'The Master of Disguise', rating: 3.3 },
]);

const goodMovies = computed(() => {
  return movies.value.filter((movie) => movie.rating > 5);
});
  
console.log(goodMovies.value.length) // 3
</script>

Sorting Array Data

<script setup>
import { ref, computed } from 'vue';

const movies = ref([
  { title: 'Jurassic Park', rating: 8.2 },
  { title: 'The Shawshank Redemption', rating: 9.3 },
  { title: 'The Dark Knight', rating: 9.0 },
  { title: 'The Master of Disguise', rating: 3.3 },
]);

const moviesOrderedByRatingDesc = computed(() => {
  return [...movies.value].sort((a, b) => b.rating - a.rating);
});
</script>

Notice we cloned the movies array

Sort alters the array its called on!

⚠️

Be careful to NEVER mutate data or trigger side effects in a computed prop

Computed values are cached based on reactive deps

Cached example

<script setup>
import { ref, computed } from 'vue';
const message = ref('Hello world');

const backwardsMessage = computed(() => {
  console.log('computing');
  return message.value.split('').reverse().join('');
});
</script>

<template>
  {{ backwardsMessage }}
  {{ backwardsMessage }}
  {{ backwardsMessage }}
</template>

This will only log once!

Common Mistake

<script setup>
import { ref, computed } from 'vue';

const randomNumber = computed(() => {
  return window.localStorage.getItem('randomNumber');
});

setInterval(() => {
  window.localStorage.setItem('randomNumber', Math.random());
}, 1000);
</script>

Expecting non-reactive deps to trigger computed to re-evaluate

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 4

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Coffee Break

β˜•οΈ

Class and Style Bindings

5

Section

You can bind classes and styles with v-bind just like any other attribute

<script setup>
import { ref } from 'vue';
const active = ref(false);
</script>

<template>
  <div :class="active ? 'is-active' : ''"></div>
</template>

Boolean Classes

<div class=""></div>

Rendered Result

<script setup>
import { ref } from 'vue';
const active = ref(true);
</script>

<template>
  <div :class="active ? 'is-active' : ''"></div>
</template>

Boolean Classes

<div class="is-active"></div>

Rendered Result

Boolean Classes

<script setup>
import { ref } from 'vue';
const active = ref(true);
</script>

<template>
  <div :class="{ 'is-active': active }"></div>
</template>

Can shorten to an object

Boolean Classes

<script setup>
import { ref } from 'vue';
const active = ref(true);
</script>

<template>
  <div :class="{ active }"></div>
</template>

Can shorten further if the class-name is the same as the reactive data

<div class="active"></div>

Rendered Result

Mix static and dynamic classes

<script setup>
import { ref } from 'vue';
const active = ref(true);
</script>

<template>
  <div 
    class="static"
    :class="{ active }"
  ></div>
</template>
<div class="static active"></div>

Rendered result

Multiple Classes as an Array

  <div class="class-1 class-2 class-3"></div>
  <div :class="['class-1', 'class-2', 'class-3']"></div>

Same as

(easier to work with if your class list is dynamic)

Can Mix Arrays and Objects

  <div :class="[ { active }, 'static' ]"></div>

Can bind to computed prop or reactive data

<script setup>
import { ref, computed } from 'vue';
const active = ref(true);
  
const classes = computed(()=>{
  return [
    'static',
    { active: active.value }
  ]
})
</script>

<template>
  <div 
    :class="classes"
  ></div>
</template>

Vue also has shortands for

Styles

<div :style="{ 
  color: activeColor, 
  fontSize: fontSize + 'px' 
}"></div>
const activeColor = ref('red')
const fontSize = ref(30)

Styles Shorthand

camelCase is recommended

<div :style="{ 
  color: activeColor, 
  'font-size': fontSize + 'px' 
}"></div>
const activeColor = ref('red')
const fontSize = ref(30)

Styles Shorthand

Kebab case is also supported
(but must have quotes)

<div :style="styleObject"></div>
const styleObject = ref({
  color: 'red',
  fontSize: '13px'
})

Can bind full reactive ref

<div :style="[baseStyles, overridingStyles]"></div>
const baseStyles = ref({ /*...*/ })
const overridingStyles = ref({/*...*/})

Can bind multiple objects that will be merged

πŸ’‘ Tip!

When you use a CSS property that requires a vendor prefix in :style, Vue will automatically add the appropriate prefix.

(Vue checks support at runtime)

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 5

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

Form Input Bindings

6

Section

Forms are the most common way of gathering user input

v-model is the primary way of interacting with form inputs

We already saw it in action

<script setup>
  const msg = ref("Hello Bootcampers!");
</script>

<template>
  <input v-model="msg">
  <div>{{msg}}</div>
</template>

v-model behaves differently based on the input type

Text Inputs

<input type="text" v-model="msg">
const msg = ref("Hello World");

Great for string data

Text Inputs

Syntactic Sugar

<input type="text" v-model="msg">
<input type="text" :value="msg" @input="msg = $event.target.value">

Textareas

<textarea v-model="msg"></textarea>
const msg = ref("Hello World");

Also great for strings

Selects

<select v-model="framework">
  <option value="Vue">Vue</option>
  <option value="React">React</option>
  <option value="Svelte">Svelte</option>
</select>
const framework = ref("Vue");

Work with strings but you want to limit options

Selects

<select v-model="framework">
  <option v-for="option in options" :key="option.name" :value="option">
    {{option.name}}
  </option>
</select>
const framework = ref({ name: "Vue", version: 3 });
const options = [
  { name: "Vue", version: 3 },
  { name: 'React', version: 'x' },
  { name: 'Svelte', version: 'x' }
]

Also works with other data types

Selects

<select v-model="framework" multiple>
  <option v-for="option in options" :key="option.name" :value="option">
    {{option.name}}
  </option>
</select>
const framework = ref([{ name: "Vue", version: 3 }]);
const options = [
  { name: "Vue", version: 3 },
  { name: 'React', version: 'x' },
  { name: 'Svelte', version: 'x' }
]

Works with arrays and the multiple attribute to allow selection of more than one option

Radio Buttons

<label> 
   <input type="radio" value="Vue" v-model="framework"/> Vue 
</label>
<label> 
   <input type="radio" value="React" v-model="framework"/> React 
</label>
<label> 
   <input type="radio" value="Svelte" v-model="framework"/> Svelte 
</label>
const framework = ref("Vue");

Works much like selects but instead of options, its inputs with the SAME v-model

<label>
  <input type="checkbox" value="Vue" v-model="framework"/> Vue
</label>

<label>
  <input type="checkbox" value="React" v-model="framework"/> React
</label>

<label>
  <input type="checkbox" value="Svelte" v-model="framework"/> Svelte
</label>
const framework = ref([]);

Checkboxes

Works with arrays (just like select with multiple attribute)

<label>
  <input type="checkbox" v-model="agree"/> I agree
</label>
const agree = ref(false);

Checkboxes

Also works with Booleans

<label>
  <input 
    type="checkbox" 
    v-model="agree" 
    true-value="Yes" 
    false-value="No"
  /> I agree
</label>
const agree = ref("No");

Checkboxes

Can customize boolean values

v-model modifiers

<!-- trims whitespace from either side -->
<input type="text" v-model.trim="msg">

<!-- auto cast to number -->
<input type="string" v-model.number="age">

<!-- number modifier not needed on number inputs -->
<input type="number" v-model="age">

<!-- lazily update the bound data via the change event-->
<!-- (when the element's value changes and then loses focus) -->
<input type="string" v-model.lazy="msg">

Questions?

πŸ™‹πŸΎβ€β™€οΈ

Exercise 6

πŸ‘©β€πŸ’»πŸ‘¨πŸ½β€πŸ’»

πŸŽ‰

That's all for day 1

Homework

Continue practicing the concepts we learned today if you choose

Official Training Module

Resources for Helping to Complete Homework

πŸ™‹πŸΎβ€β™€οΈ

Any final questions?

πŸ‘‹

See you next week!

Bootcamp Level 1 Day 1

By Daniel Kelly

Bootcamp Level 1 Day 1

  • 280