DEV Community

Cover image for A Complete Beginner's Guide to Vue
Ali Spittel
Ali Spittel

Posted on • Updated on • Originally published at welearncode.com

A Complete Beginner's Guide to Vue

Vue.js is a frontend framework that is optimized for progressive integration. That means you can have a large app with only a couple Vue components integrated -- or you could start from scratch and work completely within the Vue ecosystem.

Another thing that sets Vue apart is the lower learning curve compared to a lot of frameworks. Instead of having to understand complex topics, if you know HTML, CSS, and JavaScript, you're already pretty close!

Like any framework, it adds a structure and utilities to your frontend so that your app is easier to extend as it grows, is more organized, and you don't have to "reinvent the wheel" as often.

Vue is also really cool because it's ecosystem is really well integrated -- a lot of the utilities that would normally be 3rd party libraries are built by the Vue core maintainers, like Vue Router and Vuex.

Throughout this post, we'll explore the key features of Vue, and create an app together!

Here's what we'll be building, though with some more interactive features. The like button will toggle from the heart outline to the red heart based on user clicks. Also, the character number will count down when someone types in the text box.

Go ahead and check out the HTML and CSS code above, we'll be building off of the HTML with our Vue code.

Setting up a Vue App

For now, we'll use a Vue CDN -- we want a minimalist setup. In the future, you may want a more extensive environment, in which case you can use the Vue CLI.

Go to the settings button on Codepen, switch to the JavaScript tab, and search for Vue on CDNjs. This adds the Vue library to our project, so we can use all of the methods and features that Vue gives us.

Now, we need to create a Vue instance and attach it to our HTML in order to fully integrate Vue!

Let's create a const that stores our Vue instance.

const app = new Vue()
Enter fullscreen mode Exit fullscreen mode

We're going to pass an object when we create this Vue app, it'll have all our configuration and application logic for now.

The first thing we're going to add to that object is el -- which is the element that we want to be the base of our Vue app. In this case the element with the status class.

const app = new Vue({
  el: ".status"
})
Enter fullscreen mode Exit fullscreen mode

Then, we'll add our data. To test this out, let's add the tweetText as data -- so where we have Hello World! right now will become a variable. Down the road we're going to make more tweets with different text, so it makes sense to make that piece of the tweet dynamic.

const app = new Vue({
    el: ".status",
    data: {
        tweetText: "Hello World!"
    }
})
Enter fullscreen mode Exit fullscreen mode

When we want to add more dynamic data (or data that will change within our Vue app) we'll add more attributes to this data object.

Now, we can use our newly created data in our HTML and plug in the variables that way! If you've ever used Handlebars or another templating language, it's kind of like that.

If you go to the hardcoded "Hello World!" in the HTML, we can now replace it with {{tweetText}} which will pull from our Vue data!

<p class="tweet-text">
  {{ tweetText }}
</p>
Enter fullscreen mode Exit fullscreen mode

Try to change your tweetText in Vue, and it'll change in your output as well!

Let's brainstorm for a second on what other data we have that will change within the course of our app.

  • The heart will toggle between liked and unliked
  • Our characters remaining will decrease when we type in the

Let's go ahead and add attributes for those in our data object.

data: {
    tweetText: "Hello World!",
+    charactersRemaining: 280,
+    liked: false
}
Enter fullscreen mode Exit fullscreen mode

We'll also make charactersRemaining dynamic in the HTML.

<span class="characters-remaining">
  {{ charactersRemaining }} characters remaining
</span>
Enter fullscreen mode Exit fullscreen mode

We'll hold off on the liked attribute for now, we'll come back to that in a second.

Methods

Now that we have our data, we need to make it update based on user actions.

We're going to add another attribute to our Vue object -- this one will store our methods.

const app = new Vue({
    el: ".status",
    data: {
        tweetText: "Hello World!",
        charactersRemaining: 280,
        liked: false
    },
    methods: {}
})
Enter fullscreen mode Exit fullscreen mode

We have two "actions" for our app -- toggling the like and changing the characters remaining number when the user types. Let's work on the character counting first.

We'll add a function to our methods object first:

methods: {
    countCharacters: function() {

    }
}
Enter fullscreen mode Exit fullscreen mode

Let's think about the logic for this function: we need to count how many characters the user has typed into the textarea. Then, we need to subtract that count from 280 (or our character limit).

Let's create a data attribute for the comment text, and then update that every time the user types in the textarea.

  data: {
    tweetText: 'Hello World!',
    charactersRemaining: 280,
+    commentText: '',
    liked: false
  },
Enter fullscreen mode Exit fullscreen mode
<textarea placeholder="tweet your reply" v-model="commentText"></textarea>
Enter fullscreen mode Exit fullscreen mode

v-model is a directive that syncs our data attribute with what the user has typed into the textarea. So no matter how much or little they have typed in, commentText will match what they've typed. To take one quick step back, directives are HTML attributes that are provided by Vue, they're prefixed by v-.

Okay, now back to our method. We can access our data in our methods with this.myDataAttribute (here's a great reference on JavaScript's this).

So, we can update the charactersRemaining with the following logic:

methods: {
    countCharacters: function() {
        this.charactersRemaining = 280 - this.commentText.length
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, we need to make sure that countCharacters runs every time the user types in the textarea.

Luckily, Vue has the v-on directive, and we can add the event after it so that we run the method each time that event takes place. In this case, v-on:input="countCharacters" will run the countCharacters method each time the user types in the textarea.

<textarea
  placeholder="tweet your reply"
  v-model="commentText"
  v-on:input="countCharacters"
></textarea>
Enter fullscreen mode Exit fullscreen mode

Okay, now let's step back and work on our toggleLike method.

We first need to add the method to our methods object.

methods: {
    ...
    toggleLike: function () {

    }
}
Enter fullscreen mode Exit fullscreen mode

The body of the method should change this.liked to the opposite of what it currently is. So:

toggleLike: function () {
    this.liked = !this.liked
}
Enter fullscreen mode Exit fullscreen mode

Now we need to make that action run.

On our reactions div, let's add an event listener.

<div class="reactions like" v-on:click="toggleLike">
  ...
</div>
Enter fullscreen mode Exit fullscreen mode

It's time to introduce another Vue feature: conditionals!

Conditionals

Vue allows us to conditionally render data with the v-if directive.

Let's add the following span-wrapped emoji within our reactions div:

<span v-if="liked">♥️</span>
Enter fullscreen mode Exit fullscreen mode

Now, our red heart emoji only shows up if liked is true. Let's also add a v-else to our heart outline emoji, so that it only renders if liked is false.

<span v-if="liked">♥️</span> <span v-else></span>
Enter fullscreen mode Exit fullscreen mode

Yay! Now our likes work!

If you had any issues with the above steps, here's a Codepen with what we have so far.

Now that we have our interaction down, how would we create a bunch more tweets with the same functionality but different data? Components!

Components

Similar to other frontend frameworks, Vue apps are broken down into components. We compose components together in order to create full user interfaces. A good rule of thumb is that if a chunk of the user interface is used multiple times, it should be broken into a component.

In a production application, our tweet would probably be broken into subcomponents -- we may have a component for the comment text area, one for the like functionality, one for the profile picture, etc. But, for now, we will just make the full tweet into a component so that we can easily create a bunch more tweets.

First, let's move the logic from our Vue instance into a component.

The first argument to Vue.component is the name of the component, in this case "tweet". We're also turning data into a function that returns an object. This allows us to have multiple tweet component instance, each with separate data.

Vue.component("tweet", {
  data: function() {
    return {
      charactersRemaining: 280,
      commentText: "",
      liked: false
    }
  },
  methods: {
    countCharacters: function() {
      this.charactersRemaining = 280 - this.commentText.length
    },
    toggleLike: function() {
      this.liked = !this.liked
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

We also need the template for the component -- or the HTML that the component will render. We're going to grab all of the existing HTML and paste into a template attribute on our component.

template: `<div class="status">
  <div class="tweet-content">
    <img src="https://pbs.twimg.com/profile_images/1070775214370373633/borvu2Xx_400x400.jpg" class="logo" alt="Vue Vixens DC logo">
    <div class="tweet">
      <a href="https://twitter.com/vuevixensdc">Vue Vixens DC</a>
      <span>@VueVixensDC · Mar 20</span>
      <p class="tweet-text">
        {{ tweetText }}
      </p>
      <div class="reactions">
        <span v-on:click="toggleLike" class="like">
          <span v-if="liked">♥️</span>
          <span v-else>♡</span>
        </span>
      </div>
    </div>
  </div>
  <div class="comment-bar">
    <textarea placeholder="tweet your reply" v-model="commentText" v-on:input="countCharacters">
    </textarea>
    <span class="characters-remaining">
      {{ charactersRemaining }} characters remaining
    </span>
  </div>
</div>`
Enter fullscreen mode Exit fullscreen mode

Now, we have a Vue component!

One other quick thing we need to add: the tweet text is going to be different from tweet to tweet. We'll pass in different tweet text for each individual tweet through props -- which allow us to pass data to a component from outside of that component. For now, we'll just specify that our component has a prop associated with it.

Vue.component('tweet', {
  props: ['tweetText'],
...
})
Enter fullscreen mode Exit fullscreen mode

We still have to have a Vue app though, so let's add that back into our JavaScript:

new Vue({ el: "#app" })
Enter fullscreen mode Exit fullscreen mode

Cool, now our JavaScript is set, we just have to handle our HTML. In our Vue instance, we're looking for an element with the id app now, so let's create that.

<div id="app"></div>
Enter fullscreen mode Exit fullscreen mode

And, inside of our new Vue app, we'll add some instances of our tweet component.

<div id="app">
  <tweet tweet-text="hello world!"></tweet>
  <tweet tweet-text="hi!"></tweet>
</div>
Enter fullscreen mode Exit fullscreen mode

Notice how we're passing in our tweetText prop -- Vue converts the JavaScript camel case to kebab case in HTML. Outside of that change, our props look like HTML attributes.

Now our component should be good to go!

One more quick thing though, usually instead of hardcoding each tweet in the HTML, we're going to want to loop through a data structure and create a tweet component for each of those items. Let's look at how to do that in Vue!

We're going to go into our Vue app instance and add some tweet data.

new Vue({
  el: "#app",
  data: {
    tweets: [
        { id: 1, tweetText: "hello world!" }, 
        { id: 2, tweetText: "hi!" }
    ]
  }
})
Enter fullscreen mode Exit fullscreen mode

Now we'll use another Vue directive, v-for in order to loop through the tweets array and create a tweet instance for each!

<div id="app">
  <tweet
    v-for="tweet in tweets"
    v-bind:key="tweet.id"
    v-bind:tweet-text="tweet.tweetText"
  ></tweet>
</div>
Enter fullscreen mode Exit fullscreen mode

Notice that we use v-bind twice here -- it allows us to dynamically update html attributes (or use variables within them). Keys are recommended whenever you use v-for -- it allows Vue to identify the child elements better (more).

Awesome! Now we can create more tweets by adding an element to the tweets array!

Here's all of that code together.

More Resources to Learn Vue

First, there's a lot of cool features that you can add to the widget we just built. You can make the profile pictures different from tweet to tweet, along with the date and user data. You can also disable or highlight overflow text in our textarea. You could even use the Twitter API to use real tweets and even make the comment posting work!

Here are some more awesome resources for continuing to learn Vue:

And, if you're interested in more "Beginner's Guides" like this one, I have them for CSS and React as well!

Top comments (40)

Collapse
 
georgehanson profile image
George Hanson

Nice article! :)

You could also replace charactersRemaining with a computed property instead. That way you don't need a method to update the value or store it in the data object. For example, you could do this:

computed: {
  charactersRemaining() {
    return 280 - this.commentText.length
  }
}
Collapse
 
aspittel profile image
Ali Spittel

Totally, I did this for a workshop and I wanted two methods.

Collapse
 
andrzejchmura profile image
Andrzej Chmura • Edited

I haven't written a single line of Vue code personally, but at first glance it looks like Vue really gets out of one's way and allow to focus on business logic from the get-go. Lack of build step for prototyping is nice; however, that templating syntax brings some bad memories from Angular 1.x. I guess I should try it one day.

Also, that git diff in markdown looks cool.

Thanks for sharing!

Collapse
 
rafalolszewski94 profile image
Rafał Olszewski

Vue templating is nothing like Angular, it's butter smooth and it's best one I've played with. Better than React JSX, easier to understand, cleaner.

Collapse
 
moremooredesign profile image
Jeremy Moore

Yeah, I'm not the biggest fan of React JSX. It makes the markup tightly coupled to Javascript conventions, especially with all the maps that tend to get used.

Collapse
 
twigman08 profile image
Chad Smith

I at first wasn't sure of the templating syntax, but after using it I love it.

Though Vue does allow you to go into the render function if you wanted to go that level (and there are times for advanced components it's needed), and there is a plug-in to use JSX with Vue. So your render function is pretty much just JSX then.

Collapse
 
yaser profile image
Yaser Al-Najjar

Great intro... thx Ali !

I've always wondered: with the ease and straight-forward-ness of Vue, why people are even looking at React or Angular? just cuz it's from Facebook or Google?!

Collapse
 
revskill10 profile image
Truong Hoang Dung

Have you tried React Hooks, or React Suspense yet ? Just try it and comeback.

Collapse
 
flozero profile image
florent giraud

you have vue hook too so yes i come back :)

Thread Thread
 
revskill10 profile image
Truong Hoang Dung

OK, how about Suspense ? I couldn't live without it for my SSR application.

Thread Thread
 
twigman08 profile image
Chad Smith

I looked at it really quickly, and Vue has something very similar to it from what I understand it does (I didn't watch a talk on it or anything)

Collapse
 
fantasticsoul profile image
幻魂

yeah, hook is cool, you can also try concent composition api or hook for react!
here is an online example: stackblitz.com/edit/concent-regist...

more details see github.com/concentjs/concent
hope you like it, concent is a predictable、zero-cost-use、progressive、high performance's enhanced state management solution for react _^

Collapse
 
guykatz profile image
guykatz

Because people are religious when it comes to coding.
IMHO, Vue will take over sooner than you think...

Collapse
 
dimensi0n profile image
Erwan ROUSSEL

What a wonderful guide 🤩
Could you do the same about react ?

Collapse
 
aspittel profile image
Ali Spittel

Thank you!! I actually have one for React! dev.to/aspittel/a-complete-beginne...

Collapse
 
dimensi0n profile image
Erwan ROUSSEL

Thanks 🙏

Collapse
 
matias_e_romero profile image
Matias Romero

I think that you missed one bracked on first codepen.

Vue.component("tweet", {
Collapse
 
aspittel profile image
Ali Spittel

OOps! I totally wrote over the starter code in my workshop tonight, great catch! Reverted.

Collapse
 
matias_e_romero profile image
Matias Romero

Great! Thank you for the guide! ;)

Collapse
 
misterhamm profile image
Chris

So I'm a little ashamed to say I've spent quite a bit of time working in Vue without really understanding it. This breakdown was SUPER helpful to get my head in the right spot and back to the basics of what everything is actually DOING. Definitely one of the best Twitter follows I've made :)

Collapse
 
sobolevn profile image
Nikita Sobolev

Awesome guide!

We have an amazing project template for people who want to jump in into production-ready enterprise-scale systems: github.com/wemake-services/wemake-...

It is focused on code-quality and developer happiness, so we have a lot of tools to make your code better. And a lot of docs to make a developer better: wemake-services.gitbook.io/wemake-...

There are a lot of things to try and learn. Configured out of the box:

  • Typescript
  • Nuxt and SSR
  • Jest unit tests
  • TestCafe E2E tests
  • Gitlab CI
  • Docker for development and production
  • Linters and static analysis
  • and much more!

Check it out.

Collapse
 
matcharr profile image
kyo

Don't panic if you figure that it does not limit you at 280 character.
It's totally normal we did not add any method to make some changes if we hit 280 characters, so it will keep counting in negative number.
Anyway a very good beginner guide ;D

Collapse
 
epsi profile image
E.R. Nurwijayadi

Cool.

I also made an article about both Vue2 and Vue3 Router.

epsi-rns.gitlab.io/frontend/2020/1...

Vue Router: Hello World

Collapse
 
maxwell_dev profile image
Max Antonucci

I've used Vue for several CodePen projects in the past, but this helped clear up how to make use of components in that same context. Already looking forward to the next time I can try them out!

Collapse
 
johnhorner profile image
John Horner

"Our characters remaining will decrease when we type in the"

This sentence seems to be cut off before the end?

Collapse
 
sudoanushil profile image
Anushil Kumar

Hi ,

I need some help with migration from AnguarJs to Vue or React slowly.
I am very new to this and have very less idea.

Problem 1:
I have a doubt that how can I use vue with my current application side by side and slowly migrate the whole application to Vue. It's a very big application.

Problem 2 :
How can I tell AngularJs controller to run vue. If I am using it with AngularJs.
How will my ngRoute will serve the new vue file and run it.

Current Stack for Frontend
AngularJs, Gulp

Shift to: Vue/React with Webpack

Please help me out. I will be very thankful to you.
Please share some courses or blog if you think that are best for me to learn and grow.

Thanks & Regards,
Anushil Kumar

Collapse
 
glpzzz profile image
Gabriel Alejandro López López • Edited

Thanks for the intro! I'm totally new to Vue.js. The only thing I don't like is the way template is defined as a string on the JS. Is there any other way to do this?

Collapse
 
wsmithny profile image
{...Wayne}

Wow! Thank you. I've been wanting to learn Vue and this guide makes it easy.

Collapse
 
aimzilla profile image
Amy Pennybacker

Great, easy to follow tutorial! Thank you for this! One non-Vue related question...how/where are you getting the heart icons for the if/else like condition?? Thanks!

Collapse
 
aspittel profile image
Ali Spittel

Thanks, for sure! They're heart emojis!