A Vue.js introduction for people who know just enough jQuery to get by
By: Matt Rothenberg
Tags: Jquery, Design, JavaScript, Web Development, Vuejs

I’ve had a love-hate relationship with JavaScript for years.

I got to know the language by way of the design and development community’s favorite whipping boy, jQuery. You see, at the time I began learning JavaScript, as a “Designer who codes,” working with jQuery was a magical experience. I could make modals fadeIn and fadeOut . With a third-party library, I could add parallax scrolling to my portfolio with just a single function call. Nearly everything I could have possibly dreamed of was encapsulated in a single, ~100kb file…

And then Angular came out. I had no choice but to redo my entire portfolio with the framework. And then React came out. I had no choice but to redo my entire portfolio with the library. And then Vue.js came out. I had no choice but to redo my entire portfolio with the library… You see where this is going.

All jokes aside, I have greatly enjoyed honing my JavaScript chops through building things here and there with these different frameworks and libraries. I have read countless articles and tutorials in the process, but none has stuck with me more than Shu Uesugi’s piece, “React.js Introduction For People Who Know Just Enough jQuery To Get By.”

Shu takes readers — who are presumed to have some level of proficiency with JavaScript fundamentals and jQuery — on a journey through the world of React as they build a clone of Twitter’s “compose tweet” component.

This conceptual frame was quite helpful to me as someone who learns best by doing. Indeed, any time a new JavaScript library comes out, I find myself going back to the example from this article to test the waters. And so, I would like to borrow this frame as I step you all through my recent experience of learning Vue.

Before you begin the steps below, I highly encourage you to read Shu’s article. He does a fantastic job of walking you through the jQuery code you might write in order to implement some of these features. Thus, and so as to mitigate the risk of redundancy, I will focus on showing you the ins-and-outs of Vue.

What We’re Building

Most of us tweet (some more prolifically than others). So we are probably familiar with the User Interface component in the screenshot below.

Twitter’s “Compose Tweet” box

Believe it or not, this UI component is a great example of how Vue (and React, as per Shu) might improve your life as a JavaScript/jQuery developer. The elements of this component that we will focus on building today are:

The <textarea> where users can enter their tweet

where users can enter their tweet The <button> that is enabled/disabled as a function of how long the tweet is

that is enabled/disabled as a function of how long the tweet is A counter that indicates how many characters (out of 140) remain, and changes color to warn the user of this limit

A camera icon that, when clicked, allows users to attach photos to their tweet

A list of photos that have been attached

A button (per each photo) to remove it from the tweet

If You’re Stuck

If at any point you come across something that is confusing or poorly explained, don’t hesitate to tweet me at @mattrothenberg. Keep in mind as you read this article: it’s not you, it’s definitely me.

Let’s get started.

How We’re Building It

Today, we will be using CodePen to build our “Compose Tweet” component. For the uninitiated, CodePen is an online HTML/CSS/JavaScript editor akin to JSBin or JSFiddle. For each step, I’ll embed a CodePen with the relevant code.

Step 1: Scaffold The Project

The first thing we need to do, before writing any JavaScript, is to write the markup for our “Compose Tweet” component. Today we will be using Tachyons for almost all of our stylistic needs (so that we don’t have to write extraneous CSS, and can focus on the markup and JavaScript).

I am running with the assumption that you are pretty CSS savvy, so I will not spend time walking you through the Tachyons approach to styling (tl;dr so style, much classes, very functional).

In this CodePen I have also gone ahead and pulled in Vue via CDN. Indeed, one of the main selling points of Vue is the simplicity by which it can be integrated into a new or existing codebase.

With everything in place, let us get started on some feature work.

Step 2: Implement the First Feature — Tweet Button Should Initially Be Disabled

To Disable or Not To Disable, that is the question

Feature Description: Disable the blue Tweet button until a user has entered at least one character in the textarea .

First things first, let us set up our Vue instance. As mentioned above, Vue has won the hearts and minds of Developers by its simplicity of installation and ease of use. We can construct a Vue instance with the following code.

new Vue({

el: '#twitterVue',

data: {

tweet: ''

},

computed: {

tweetIsEmpty: function() {

return this.tweet.length === 0;

}

}

})

Let me explain what is going on here —

el refers to the DOM element to which we are attaching our Vue instance. This should feel similar to instantiating a jQuery plugin by passing in a given selector, be it a class name or ID.

refers to the DOM element to which we are attaching our Vue instance. This should feel similar to instantiating a jQuery plugin by passing in a given selector, be it a class name or ID. data is an object that describe’s our instance’s data model, or state. We can access the attributes specified within this model both in our HTML — via a special curly brace syntax {{tweet}} — and within the instance itself (hint, look at the body of the tweetIsEmpty function)

is an object that describe’s our instance’s data model, or state. We can access the attributes specified within this model both in our HTML — via a special curly brace syntax — and within the instance itself (hint, look at the body of the function) computed is an object that describes, as you might guess, computed properties based on our data model. Instead of adding logic to our HTML, it is recommended to encapsulate this kind of state (or any derived value, for that matter) via functions defined on the computed key of our Vue instance.

Turning our attention now to the HTML, you will see that our markup has changed ever so slightly from the first CodePen. Specifically, we have made three changes.

We added the id twitterVue to the outermost div so that we could construct our Vue instance.

<div id="twitterVue">...</div>

2. We added the v-model directive to our textarea , thereby creating a two-way binding between user input and our instance’s data model. Now, any time a user types in the textarea , the tweet attribute on our instance’s data model is automagically updated.

<textarea v-model="tweet"></textarea>

3. We added the :disabled attribute to our button . The colon preceding disabled denotes that we would like to evaluate the content inside the quotes as a JavaScript expression. If we were to omit the colon, the content would be treated as a string. You’ll also note that we’ve added a few lines of CSS to give the disabled button a distinct visual styling.

<button :disabled="tweetIsEmpty">Tweet</button> ... button[disabled] {

cursor: not-allowed;

opacity: .5;

}

4. We also added a computed property on our instance called tweetIsEmpty . Note that this property is actually a function that returns a boolean value based on the length of our data model’s tweet attribute. Vue makes it dead simple to access your data model both in the HTML (as shown above) and in the instance itself. Thanks to the magic of two-way data binding, this function is evaluated when the value of tweet is updated. When the function evaluates to true, our button is disabled, and vice-versa.

tweetIsEmpty: function() {

return this.tweet.length === 0;

}

Admittedly, this felt like smoke and mirrors when I first got started with Vue. What helped me was to literally see what was happening to our data model under the hood as I interacted with the component. Since we can easily access our data model in our HTML via the aforementioned curly brace syntax, we can build a quick, visual feedback loop. Score!

<p>The value of <strong>tweet </strong>is: {{tweet}} </p>

<p>The value of <strong>tweetIsEmpty</strong>is: {{ tweetIsEmpty}}</p>

Visual Learning

Please feel free to repeat this step if anything along the way was confusing (either due to my poor writing or coding abilities, or due to Vue itself). Send a tweet or leave a comment if you have any particular questions.

Step 3: Implement the Second Feature — Show The Number of Characters Remaining

140 Characters or Bust!

Feature Description: As a user types, show the number of characters remaining (out of 140) in the tweet. If a user has entered more than 140 characters, disable the blue Tweet button.

So far we have learned about two-way data binding and computed properties, concepts that are at the very core of Vue. It is our lucky day, because we can leverage these concepts to build our next feature: showing the users how many characters (out of 140) remain, and disabling the button if this limit is eclipsed.

Once again, I will step you through both the JavaScript and HTML changes required to implement this feature.

In our JavaScript, we have done a few things.

As a housekeeping measure, we enumerated the max length of a tweet (140 characters) as a constant, MAX_TWEET_LENGTH .

const MAX_TWEET_LENGTH = 140;

2. We added another computed property, charactersRemaining , which dynamically returns the difference between 140 and the length of the user-entered tweet.

charactersRemaining: function() {

return MAX_TWEET_LENGTH - this.tweet.length;

}

3. We renamed the old tweetIsEmpty property to tweetIsOutOfRange and updated the function’s logic accordingly. Note how we are using the computed charactersRemaining property to derive this value. Hooray for code reuse!

tweetIsOutOfRange: function() {

return this.charactersRemaining == MAX_TWEET_LENGTH

|| this.charactersRemaining < 0;

}

On the HTML side of things, we only have to make a few changes, thanks to the power of Vue’s two-way data binding.

<div class="flex items-center">

<span class="mr3 black-70">{{ charactersRemaining }}</span>

<button :disabled="tweetIsOutOfRange" class="button-reset bg-blue bn white f6 fw5 pv2 ph3 br2 dim">Tweet</button>

</div>

For the visual learners out there, watch the magic:

Step 4: Implement the Third Feature: Conditional Styling of “Characters Remaining” indicator

Feature Description: When composing a Tweet, the color of the “characters remaining” indicator should change to dark red when only twenty characters remain, and light red when ten or fewer remain.

Manipulating an element’s style or class can be cumbersome with jQuery, and Vue offers a much cleaner way of doing so. Vue’s approach feels more declarative, in that you describe how you want something’s style to change (based, for example, on a given state) and you let Vue do the heavy lifting.

In the context of this feature, our “characters remaining” indicator has two such states, and a corresponding CSS class for each.

When between ten and twenty characters remain, the indicator should have the dark-red class When fewer than ten characters remain, the indicator should have the light-red class

By now your Vue brain should be shouting “COMPUTED PROPERTIES!” So, let us oblige this brain and wire up those properties.

underTwentyMark: function() {

return this.charactersRemaining <= 20

&& this.charactersRemaining > 10;

},

underTenMark: function() {

return this.charactersRemaining <= 10;

}

With our logic in place, let us take a look at one of the ways in which Vue handles conditional styling: the v-bind:class directive. This directive expects an object whose keys are CSS classes, and whose values are the corresponding computed properties.

{ 'dark-red': underTwentyMark, 'light-red': underTenMark }

By adding the directive to the span tag that encloses our “characters remaining” indicator, we have completed our feature.

<span

v-bind:class="{ 'dark-red': underTwentyMark, 'light-red': underTenMark }">

{{ charactersRemaining }}

</span>

Under the hood, and thanks to two-way data binding, Vue will handle the addition and removal of these classes as a function of the specified computed properties.

Goodbye, addClass() and removeClass()

Step 5: Implement the Fourth Feature: “Attach Photo” UX

Feature Description: Allow users to attach a single photo to their tweet via a file picker dialog. When the photo has been uploaded, show it beneath the textarea , and allow users to delete the attachment by clicking the image

Fair warning: there is a lot going on in this section. The beauty is, despite this feature adding considerable functionality, we will not have to write that much code. So, let us start by breaking down the interaction design into steps.

User clicks the “Add Photo” button User sees a file picker dialog and can select one photo to upload Upon selecting the photo, a box appears underneath the textarea with the selected photo inside User clicks the circular X button to remove the photo User sees initial state from step 1

Up to this point, we have not yet done any event handling (listening to button clicks, input changes, etc). As you might expect, Vue makes it easy to handle such events by affording us the v-on directive (@ for short). By passing a method as a value of this directive, we can effectively listen to DOM events and run JavaScript when they are triggered.

Before diving into our feature work, some rapid-fire practice.