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
- Intro to Vue
- Template Syntax
- Event Handling
- Reactivity Fundamentals
- Class and Style bindings
- Form Input Bindings
Section Topics
Day 2
- Component basics
- Lifecycle hooks
- Slots
- Watchers
- Template refs
- Transitions
- 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?
- With the mustache syntax
- 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
- There are links in the training module to the relevant Vue.js docs
- The Vue.js Fundamentals with the Composition API Course
- Vue.js Transitions and Animations Course
ππΎββοΈ
Any final questions?
π
See you next week!
Bootcamp Level 1 Day 1
By Daniel Kelly
Bootcamp Level 1 Day 1
- 280