Vue.js is arguably one of the easiest and most minimalist JavaScript frameworks with which to get started. While we cannot downplay the current momentum and volume of developers adapting Vue.js, you will agree with me that there are very few tutorials that cover advanced concepts in Vue.
In this tutorial, we will talk about:
- Vue.js mixins
- Custom directives
- Filters
- Transitions (enter/leave)
- State management
- Server-side rendering
Note: Vue in this tutorial refers to Vue.js 2.x versions
Setting up our environment
To get started, and also to skip the process of configuring webpack for the compilation from ES6 to ES5, we will use Vue CLI. If you do not have the Vue CLI installed, install it!
sudo npm install -g vue-cli
Vue mixins
Mixins are chunks of code which we can reuse. Think of it as a way of adhering to the DRY principle. DRY is an acronym that stands for “Don’t Repeat Yourself”.
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.
The easiest way to understand how Vue mixins work is to actually work with them. Consider two components: “A” and “B”. Both filter for users based on the date created in their lifecycle. The function which filters for users based on their creation date would appear in the two different components, causing you to repeat yourself.
As we’ve discussed, that’s bad. But there’s an easier way to filter for users based on the date created AND avoid being repetitive. Any guesses?
Vue mixins. Good guess.
Keep in mind that the more repetitive you are, the more prone you are to errors. Let’s write some code.
First, let’s create a new project by running:
#create a new project
vue init webpack mixins
#change into the new project
cd mixings
#install npm packages
npm install
Once we are done with the above code, let’s go ahead and edit our src/components/hello.vue
to:
Let’s take a quick look at the code block above. In our template section, we have one H2 tag with the content inactive users. Next, we have an ul tag with a looped li tag which prints out the name and age of each user who is inactive.
Now take a look at the script section. Notice we have a normal Vue component instance. In our data section, we have two properties which are status, and an array called users.
In our methods section, we have two methods: get_active_or_inactive
which gets all the active users based on our status and filter_by_date
 . This returns an array of users in ascending order based on the created_at
property.
Finally, we have the computed section, that comprises one method called inactiveUsers
which calls both the get_active_or_inactive
and filter_by_date
function.
We understand what our hello component now does, but we might still wonder what the goal is. The goal is to have two components, one that displays active users and one that displays inactive users. The two codes will have both the get_active_or_inactive
method and also the filter_by_date
method (which is repetitive).
So, we use Vue mixins to unify those repetitive functions.
Next, we’ll create a new component called Active.vue
and place the following contents into it:
If we look at the Active component above, the main changes from are hello component are:
- The status property in data changed from 0 to 1
- The computed property changed from inactiveUsers to activeUsers
Let’s unify the repetitive code into a mixin. To do this, create a new directory called mixins in our src
folder. Next, create a file called firstMixin.js
into our src/mixins
folder and paste in:
Notice that in the code snippet above, it is the same as a new Vue component. In fact, we only moved the methods part of our two components into this new component like structure.
We will then need to alter our components to use this mixin as seen below:
Looking at the two components above, the difference from the original components is:
- we no longer have our methods in our component
- we added an import of our mixin to the script
- we declared our mixin in the mixins section of our components
Let us bring all of this together and see if it works. To do this, replace our app.vue
file with:
The only difference with the above app.vue
file from the original app.vue
file is:
- we have imported our active component and declared it in our components section
- we have also rendered our active component to the browser
If we run the npm run dev command on our terminal, and browse to http://localhost:8080/ we should see the following:
Custom directives
Everyone has heard about directives. You most likely cannot build a feature rich app with Vue without using directives like v-if
, v-for
, v-show
, etc.
In this section, we will learn how to build a custom directive called v-test
. This function replaces the text given to it with base64 representation of its text.
Directives are tiny commands you can attach to DOM elements. They are prefixed with v- to let the library know you’re using a special bit of markup and to keep syntax consistent. They are typically useful if you need low-level access to an HTML element to control behavior.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to use the React children prop with TypeScript
- Explore creating a custom mouse cursor with CSS
- Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
First, create a new project by running:
#create a new project
vue init webpack customdirectives
#change into the new project
cd customdirectives
#install npm packages
npm install
Next, open our src/main.js
file and add the following code just before our app is declared:
In the above directive, we have listened for the insert
hook of the element which our directive is being attached to. We modify both the color and background style properties of the element. Next, we defined a function that decodes a string into base64
encoding, then we then change the HTML of the element into the result of our function.
While this may seem confusing because of the inserted
hook we have used, where exactly did the inserted hook come from?
According to the Vue documentation, there are called “hook functions”, and are explained below:
- bind: called only once, when the directive is first bound to the element. This is where you can do one-time setup work
- inserted: called when the bound element has been inserted into its parent node (this only guarantees parent node presence, not necessarily in-document)
- update: called after the containing component’s VNode has updated, but possibly before its children have updated. The directive’s value may or may not have changed, but you can skip unnecessary updates by comparing the binding’s current and old values (see below on hook arguments)
- componentUpdated: called after the containing component’s VNode and the VNodes of its children have updated
- unbind: called only once, when the directive is unbound from the element
Basically, the hook we call largely depends on the time and manner we want our action to take place. In this directive, we want it to take place after the element has been inserted into its parent node.
Our src/main.js
should look this way:
Does the new directive work? Let’s find out.
Move into src/components/Hello.vue
and use the v-test
directive on an element, such that our component now looks like this:
In the code above, we have applied the v-test directive on the first H1 and H2 element in our template.
If we run our current code base, we should end up with the following screen:
Filters
A Vue filter is essentially a function that takes a value, processes it, and then returns the processed value.
Filters are usable in two places: mustache interpolations and v-bind
expressions. Filters should be appended to the end of the JavaScript expression, denoted by the pipe (|) symbol.
We want to write a filter that will capitalize every first word of whatever string we put into it. If, for example, we want the string hi there
to start with a capital H and T.
First, create a new project by running:
#create a new project
vue init webpack customfilters
#change into the new project
cd customfilters
#install npm packages
npm install
Next, let us open our src/main.js
file and add the following code just before our app is declared:
Vue.filter('camel',function(str){
return str.toLowerCase().replace(/^\w|\s\w/g, function (letter) {
return letter.toUpperCase();
})
})
In the Vue filter we have defined above, we first convert the entire string to lower case, then check the first letter of the entire string and check the first letter that have a space character before and replaces it applying.
toUpperCase()
method.
Our src/main.js
main should look like this:
Next, we need to test our filter that it works as it should. To do this, open src/components/hello.vue
file and replace it with:
What changed?
The value of msg
in our data section. Also, we have applied the camel
filter when displaying the msg
value on our first h1
in our template.
If we run our code now, we should see:
Notice that the first letter of every word in our msg
variable is capitalized.
Transitions (Enter/Leave)
Transitions are effects that can be applied when elements are inserted, updated, and removed from the DOM.
The simplest way to achieve transition effects on your page is through Vue’s <transition>
component. The <transition>
component is made globally acceptable by Vue, which means it can be used and accessed within any component.
Vue works by adding and removing classes on elements during the transition process.
There are six different class prefixes while dealing with transitions which are:
- -enter: contain styles for when the element begins to appear at the scene
- -leave: contain styles for when the elements begins to leave the scene
- -enter-active: styles for when the transition is in place e.g transition seconds
- -leave-active: styles for when the transition is getting out of place e.g transition seconds
- -leave-to: This replaces -leave
- -enter-to: This is the ending class for enter. It is applied when -enter is removed
All we need to do for us to use transitions nicely is to add a style using any of the prefixes to the name of our transition. For example, if we have a transition named test
 , we can use them like this:
.test-enter-active {
transition: transform 3s;
text-shadow:0px 5px 10px #fdff00;
}
.test-leave-active {
transition: transform 3s;
text-shadow:0px 5px 10px #a1a194;
}
.test-enter, .test-leave-to {
transform: translateX(90%);
}
.test-enter-to, .test-leave {
transform: translateX(-15%);
}
First, create a new project by running:
#create a new project
vue init webpack transitions
#change into the new project
cd transitions
#install npm packages
npm install
Next, replace our src/components/hello.vue
with:
In the code block above, we wrapped our first h1
element with a transition called “test”. We also created a new input element, which is a button that toggles the status variable, forcing our element to enter the “leave” and “enter” states.
In our script section, we added a new variable called status
which is false by default. Next in our mounted call, we set it to “true”.
If we run our code base, we should observe that it works as shown in the image below:
State management
When your Vue application grows bigger and consists of multiple components you might run into the problem of how to share data across the those components and make sure that components which are using the same data are always updated if data changes.
Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions between them. To solve this problem, Vue offers vuex
What is Vuex?
According to the official documentation for Vuex, it is a state management pattern and library for VueJS applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only get mutated in a predictable fashion.
Vuex uses a centralized state management by implementing the following core concepts:
- State: An object containing the data
- Getters: Used to access data from the state tree of the store
- Mutations: Handler functions that perform modifications of data in the state tree
- Actions: Functions that commit mutations. The main difference to Mutations is that Actions can contain asynchronous operations
Let’s put these theories into practice.
First, let’s create a new project by running:
#create a new project
vue init webpack statemanagement
#change into the new project
cd statemanagement
#install npm packages
npm install
Next, we will install the Vuex library:
npm install Vuex
Once Vuex is installed, let’s explore our state
, actions
, mutations
, and getters
for our sample application.
When we explained what a state was, we said it was an object which contains data. If we look at the code above, we can see it is an object which contains an array of users.
Look at our actions:
actions: {
ADD_USER: function({ commit }, new_user) {
commit("ADD_USER_MUTATION", new_user);
},
DELETE_USER: function({ commit }, user_id) {
commit("DELETE_USER_MUTATION", user_id);
}
}
In our actions section, we define two functions:
- ADD_USER:This function further commits a mutation called
ADD_USER_MUTATION
with the new user object it has received as an argument which will add a new user to the list. - DELETE_USER: This function further commits a mutation called
DELETE_USER_MUTATION
with the user id it has received as an argument which will delete a user from the list.
We now move into our mutations:
mutations: {
ADD_USER_MUTATION: function(state, new_user) {
state.users.push(new_user);
},
DELETE_USER_MUTATION: function(state, user_id) {
state.users.splice(user_id,1);
}
}
In the above code, we have our mutations, which directly alter the state of our store. Inspecting the code, we notice two functions:
- ADD_USER_MUTATION: This mutation pushes a new user into our list of users
- DELETE_USER_MUTATION: This mutation deletes an object from the array of users based on the id passed, which is the index of that object.
Now lets take a look at our getters:
getters: {
users: state => {
return state.users;
}
}
In our getters
block, we define one function:
- users: This getter returns all users in our store
Next, let’s merge the concepts together to create our Vuex store.
Create a new file in our src
folder called store.js
and place in:
That’s how easy it is to get a Vuex store set up. Now to move into using this store in our application.
To notify Vue about our central store, we need to pass in the store object to our Vue instance while creating it. To do that, replace the content of our src/main.js
with:
If you look at the code above, you will notice the import of our store component, and passing it to our Vue component.
Let’s change the Hello
component so we can interact with our store.
Now, replace the content of src/components/hello
with:
In the code block above, you notice we have declared set of HTML elements, in which we can find:
- A text input which holds a new user name.
- A text input which holds a new user age.
- A text input which holds a new user status.
- A text input which holds a new user date created.
- A button element, to which we have attached a function, that adds a new user.
- UL tags, coupled with LI tags for displaying users alongside a delete button.
We are now done reviewing the HTML part of our component.
It’s important to review our methods
and computed
properties so we can see how we interact with Vuex.
Within our methods, we will notice two functions which are:
add_user
: This method dispatches the currentuser
object to the store action calledADD_USER
delete_user
: This method receives a parameter and then dispatches the parameter to the store action calledDELETE_USER
Moving into our computed properties, we have only one function called users
. This function returns all the users in our store.
If we run our code-base, it should work as shown below:
Server-side rendering
One downside of Vue as a JavaScript framework is that the page isn’t viewable until the browser has executed the app’s JavaScript bundle.
This causes apps to render blank pages and in some, keep showing a preloader for an awfully long time. The Vue team sought to solve this issue and came up with Server-side rendering known as SSR. Luckily for us, there is detailed info on how to implement server-side rendering in Vue available here.
Conclusion
In this tutorial, we covered a lot of advanced techniques using Vue. We also learned about creating and using mixins to stop code repetition. Lastly, we learned about custom directives, filters, transitions, state management, and server-side rendering.
I hope whatever you learned here will go a long way to help in writing more productive Vue applications.
The code base to this tutorial is available in this public GitHub repo. Please download for educational purposes.
Experience your Vue apps exactly how a user does
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps, including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.