Welcome! Let's learn a bit about Vue.js with this interactive demo, shall we? 🤓
Here's a quick preview: try editing the title in the text input field.
data: { name: '{{name}}'}
✨ That magic is all Vue! Let's learn how to set it up.
One of the great things about Vue is how easy it is to get started! There are only two steps, really:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js"></script>(If you're using Vue here on CodePen, you can just add it as an External Script in the JS cog menu.)
el
; this will load our Vue instance into an element on the
page (using a CSS/jQuery style selector), and swap out that element's contents with our Vue
instance's template:
const app = new Vue({ el: '#app' //We'll add more options here shortly });
The above code replaces the element that has the ID of app
with our new Vue instance.
This makes it easy to inject as much or as little Vue functionality as you want into any page or
app!
However, our Vue instance doesn't do anything just yet. For that, we'll need an HTML template for Vue to render, and we'll probably want some dynamic data to use in that HTML…
Vue stores its data inside the data
property of the Vue instance. The data
object can hold any type of values (strings, numbers, booleans, arrays, etc.):
const app = new Vue({ el: '#app',data { name: '{{name}}', demoData: '{{demoData}}', clickCount: {{clickCount}}, favoriteSites: ['CodePen', 'GitHub', 'Codecademy', 'VueJS'] }});
This lets you build pages dynamically, so that if the value changes, your HTML will update to reflect the
change. You can reference any property inside of data
easily with "handlebar" syntax, just
by using the property name:
<p>Here's some Vue data: { {demoData} } </p>
Here's some Vue data: {{demoData}}
If you're working here on CodePen, you can enter your template code directly into the HTML
pane. Nifty! That's what I've done here, but otherwise, you'll need to put your HTML template code into
a template
property in the Vue object.
Here's the cool part: Vue lets you easily create two-way data binding between form elements and Vue data, so that when either is updated, they automatically stay in sync!
This is done with the v-model
directive (which is attached to an HTML attribute—in
this case, value
).
Here's how that looks. Edit the input below and watch the above examples change, too!
<input v-model:value="demoData" /><p>The input says: { {demoData} }</p>
const app = new Vue({ el: '#app', data { name: '{{name}}',demoData: '{{demoData}}',clickCount: {{clickCount}}, favoriteSites: ['CodePen', 'GitHub', 'Codecademy', 'VueJS'] } });
The input says: {{demoData}}
Vue allows you to easily watch for and react to events like clicks, user input, form changes and more
(without the need to mess with typical JavaScript event listeners). This is done with the
v-on
attribute, which is attached to the event you'd like to watch for (in
this case, "click").
<button v-on:click="updateClickCount">The button has been clicked { {clickCount} } times. </button>
There are many types of events your Vue instance can "listen" for: click
,
change
, input
, keydown
and many more. But they're not super
useful without…
As you might have realized, v-on
lets us track events, but we'll still need to
create a function to run whenever those events happen.
Vue lets you define any number of methods in (what else?) the methods
property. Any methods there can simply be called by name.
So at this point, our code might look like this (with the new methods
property highlighted,
and added to our button with v-on:click
):
<button v-on:click="updateClickCount">This button has been clicked { {clickCount} } times. </button>
const app = new Vue({ el: '#app', data { name: '{{name}}', demoData: '{{demoData}}',clickCount: {{clickCount}},favoriteSites: ['CodePen', 'GitHub', 'Codecademy', 'VueJS'] },methods: { updateClickCount: function(){ this.clickCount += 1; } }});
You might notice that the keyword this
refers to the Vue instance. In our
templates, calling a data property with handlebar syntax ({{property}}
) works perfectly.
But when running JS from within the Vue instance, we'll need to specify the scope, with
this.property
.
Oftentimes, we'll have arrays of data in our Vue instance that we need to loop over to display in our
HTML. Vue makes this a breeze with the v-for
directive!
<ul><li v-for="site in favoriteSites">{ {site} }</li></ul>
Voilà! Multiple <li>
tags with a simple line of Vue code!
As you might have guessed, if you have an array of objects, v-for
allows you to use each
object property separately by using it with dot notation:
favoriteSitesDetails: [ {name: 'CodePen', url: 'https://codepen.io'}, {name: 'GitHub', url: 'https://github.com'}, {name: 'Codecademy', url: 'https://www.codecademy.com'}, {name: 'VueJS', url: 'https://vuejs.org'} ]
<ul><li v-for="site in favoriteSitesDetails"> <a href="site.url">{ {site.name} }</a> </li></ul>
We've got a little bit of an issue here, though. Let's find out why!
If you tried clicking any of those links above, you noticed a problem: all of the links go to
site.url
.
That's not a real URL, and it's not what we meant when we wrote the href
value. We want the
attribute's value to be dynamic, not what we literally typed. But we can't use handlebar syntax for HTML
attributes, so what can we do?
Easy! Just use the v-bind
attribute to indicate that the
attribute's value is dynamic Vue data, and not the literal typed value.
<ul> <li v-for="site in favoriteSitesDetails"><a v-bind:href="site.url">{ {site.name} }</a></li> </ul>
Note that v-bind
is very much like v-model
, but unlike
v-model
, v-bind
is one-way data binding (not two-way). This
means that changing the JS will update the HTML, but not the other way around. This makes
v-bind
a good choice for non-interactive elements.
(You could add an event and
a method to make v-bind
two-way, but at that point, it's probably better to just use
v-model
instead wherever possible.)
As you can imagine, you could often end up using lots of v-on
and v-bind
directives in your Vue templates. To make the code a little cleaner in these cases, Vue offers shorthand
for both.
v-bind
is :
:href="url"
).v-on
is @
@click="updateClickCount"
).Here's an example using both shorthands, and using v-bind
(or, :
) to
conditionally add attributes to elements based on a data
boolean.
<p :hidden="!isAlert" class="alert">🚨ALERT!</p><button @click="toggleAlert">Toggle alert</button>
data: {isAlert: {{isAlert}},}, methods: {toggleAlert: function(){ this.isAlert = !this.isAlert; }}
🚨ALERT!
The real power of binding attributes comes with conditional statements. Let's check out how you can dynamically add classes to elements with a ternary expression!
<p:class="isAlert ? 'alert' : 'default'">My class is: { {isAlert ? 'alert' : 'default'} }</p><button@click="toggleAlert">Click to toggle class</button>
data: { isAlert: {{isAlert}} }, methods: { toggleAlert: function(){ this.isAlert = !this.isAlert; } }
My class is: {{isAlert ? 'alert' : 'default'}}
Having logic in our HTML templates makes things pretty messy though. There must be a better way, right?
There sure is! Let's look at…
As we just saw, having a ternary operator in the middle of our HTML—while it worked well—made things a little tough to read. Good news: that's what computed properties are for!
A computed property is just a function that returns a "computed" value; something that needs to be obtained through an expression. (For example, adding two numbers together, concatenating strings, or in our case: examining a boolean and returning a certain string based on its value.)
So if we want to add the "alert" class to an element when isAlert
is true, and a "default"
class when isAlert
is false (as above), we can tuck that logic away in a computed function
(named getClass
, in this case) to keep our template file tidy.
<p:class="getClass">My class is: { {getClass} }</p><button@click="toggleAlert">Click to toggle class</button>
data: { isAlert: {{isAlert}} }, methods: { toggleAlert: function(){ this.isAlert = !this.isAlert; } },computed: { getClass: function(){ return this.isAlert ? 'alert' : 'default'; } }
My class is: {{getClass}}
Note that nothing has changed here functionally. This still works exactly as it did before. But now, we have a simple, reusable way to figure out if the "alert" or "default" class should be used, which renders our template file (pun intended) much more readable.
So what's the difference between a computed property and a plain ol' method? Well, in a
nutshell:
• Methods can be called at will, can be supplied arguments, and can do anything
(including update data
values).
• Computed properties aren't called; they're just used in templates. They don't take
arguments, and only return a value. In other words (appropriately), they just compute;
they don't change things. (Vue also caches them, so they're more performant.)
We're getting close to the end! One last thing I want to cover: rendering elements conditionally.
The v-if
directive allows us to use logic in our templates. For example,
let's say we want to show the user one element if loading
is true, then swap it out for
another once loading
is false:
<p v-if="loading">⏳ Loading...</p> <p v-else>✅ Loaded!</p> <button @click="toggleLoading">Toggle Loading</button>
data: { loading: {{loading}} }, methods: { toggleLoading: function(){ this.loading = !this.loading; } }
⏳ Loading...
✅ Loaded!
As you might expect, Vue also offers a v-else-if
directive, so that you can string together
complex conditions based on data!
<strong>My rating: </strong> <span v-if="rating == 1">☹️Bad.</span> <span v-else-if="rating == 2">😐Not good.</span> <span v-else-if="rating == 3">🙂Ok</span> <span v-else-if="rating == 4">😄Good</span> <span v-else>😍Great!</span> <input type="range" min=1 max=5 v-model:value="rating">
data: { rating: {{rating}} }
My rating:
☹️Bad.
😐Not good.
🙂Ok
😄Good
😍Great!
Note: elements using v-if
, v-else-if
and
v-else
must be sequential sibling elements in order to work together properly. Any element
between them will break the chain.
This guide hopefully offers a great way to get started with Vue, but there's a world of possibilities we haven't even discussed yet (including using Vue to create components)!
If you'd like to continue learning Vue, here are a few resources I found helpful:
I hope this guide has been fun and helpful. Thanks for reading! 👋😄