This content originally appeared on Telerik Blogs and was authored by Thomas Findlay
jQuery used to be a common choice for a lot of applications in the past. However, there are smaller, faster, more feature-rich solutions now. We’ll cover how to migrate from jQuery to Vue 3 a lot of common use cases, such as handling events, forms, API requests, conditional and dynamic content, and more.
In the past, for many years, jQuery was the staple choice for any kind of project. It provides a lot of useful helper methods for traversing the DOM, animations, API requests and more. What’s more, it ensures cross-browser compatible functionality, which was quite a big deal in the past, as browsers vendors did not implement features in a consistent way.
However, jQuery was not a silver bullet, and there were problems with it as projects grew. For instance, the code written in jQuery was imperative, and it was very easy to end up with a lot of nested spaghetti code. We had to update the DOM manually every time we needed to make a change. Modern frameworks, such as Vue, React, etc., have simplified this and allowed us to write declarative code. For example, instead of explicitly specifying how the DOM should be updated, we only need to write how the DOM should look, and modern frameworks will handle the rest for us.
In this article, we will cover a few common use cases and how to migrate them from jQuery to Vue 3.
Adding jQuery and Vue to a Project
Adding jQuery to a project is very simple, as we can do it by including one script tag.
<body>
<div id="app">
<!-- Content goes here -->
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- other scripts -->
</body>
The most popular ways to create a Vue project usually involve a toolchain, such as Vue CLI or Vite. However, Vue is a progressive framework and can be used without all the bells and whistles. It’s especially useful when you want to slowly migrate to Vue or if you want to add some dynamic interactions here and there in your app. Similarly to jQuery, it can be added to a project with just a script tag.
<body>
<div id="app">
<!-- Content goes here -->
</div>
<script src="https://unpkg.com/vue@3.2.21"></script>
<!-- other scripts -->
</body>
Now that we covered how to include jQuery and Vue in a project, let’s have a look at common use cases jQuery usually was used for and how to do them in Vue.
Handling Event Listeners
Handling event listeners is the first common use case. For example, if a user clicks on a button, we might want to perform some kind of action like showing a modal, or if a user focuses an input field, we could display a helpful tooltip.
In jQuery, before running any code, we would wait for the document to be ready by using the $(document).ready()
method. Then, to add event listeners, we would retrieve DOM elements by using the $('selector')
method and then chain
an event we want to listen to, such as click
or focus
. Below you can see an example.
<button id="clickMeBtn">Click me</button>
<div style="margin-top: 1rem">
<label>Focus me</label>
<input type="text" id="focus-input" />
</div>
<script type="text/javascript">
$(document).ready(() => {
$("#clickMeBtn").click(() => {
console.log("Button clicked");
});
$("#focus-input").focus(() => {
console.log("Input focused");
});
$("#focus-input").blur(() => {
console.log("Input lost focus");
});
});
</script>
When using Vue, we first need to create a Vue app by using the createApp
method and mount it on a DOM element. Vue will take control over all DOM manipulations inside of that element.
A great thing about Vue is that in comparison to jQuery, the code we write with Vue is declarative, not imperative. While in jQuery we have to explicitly retrieve DOM elements to attach event listeners, we don’t have to do that with Vue. Rather,
we only have to specify what events should be attached to an element by using the v-on
directive, and Vue handles the rest
for us (@
is a shorthand for v-on
) . Below you can see the code example for Vue.
<div id="handling-events">
<button @click="onBtnClick">Click me</button>
<div style="margin-top: 1rem">
<label>Focus me</label>
<input
type="text"
id="focus-input"
@focus="onFocusInput"
@blur="onFocusBlur"
/>
</div>
</div>
<script type="text/javascript">
const app = Vue.createApp({
setup() {
return {
onBtnClick() {
console.log("Button clicked");
},
onFocusInput() {
console.log("Input focused");
},
onFocusBlur() {
console.log("Input lost focus");
},
};
},
}).mount("#handling-events");
</script>
Again, we have handlers for three events. We listen for a button click and focus and blur events on the input element by attaching the @click
directive to the button and focus
and @blur
directives on the input. All
the directives receive appropriate handlers that are defined in the setup
method: onBtnClick
, onFocusInput
and onFocusBlur
. Anything that is returned in an object from the setup
method
will be available in the markup.
A nice advantage of Vue that I think is worth mentioning here is, when we look at the DOM markup, we can clearly see what kind of events we are listening to, as the directives are defined directly on elements. With jQuery, however, this isn’t the case. To figure out what events we are listening to, we would need to dive into the jQuery implementation.
Handling Forms
A lot of websites contain forms for the sign-up, login, contact, etc. With jQuery, we explicitly query for the form
element by using its id
and then attach a submit
event listener. Then, to get access to input values,
we retrieve them directly and get their values using the val()
method.
<div id="login-form-container">
<form id="login-form">
<div class="form-row">
<label for="email">Email </label>
<input type="email" name="email" />
</div>
<div class="form-row">
<label for="password">Password </label>
<input type="password" name="password" />
</div>
<div>
<button type="submit">Submit Form</button>
</div>
</form>
</div>
<script type="text/javascript">
$(document).ready(() => {
$("#login-form").submit(e => {
e.preventDefault();
const email = $('[name="email"]').val();
const password = $('[name="password"]').val();
console.log("form submitted", {
email,
password,
});
});
});
</script>
Vue is a reactive state-driven framework. In a nutshell, Vue will create and update the DOM based on the reactive state, instead of us doing it imperatively. There are a few ways to create a reactive state, and one of them is by using the ref
method.
<div id="login-form-container">
<form id="login-form" @submit.prevent="onSubmit">
<div class="form-row">
<label for="email">Email </label>
<input v-model="email" type="email" name="email" />
</div>
<div class="form-row">
<label for="password">Password </label>
<input v-model="password" type="password" name="password" />
</div>
<div>
<button type="submit">Submit Form</button>
</div>
</form>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const email = Vue.ref("");
const password = Vue.ref("");
const onSubmit = () => {
console.log("form submitted", {
email: email.value,
password: password.value,
});
};
return {
email,
password,
onSubmit,
};
},
}).mount("#login-form-container");
</script>
We have two reactive refs: email
and password
. Both of them and the onSubmit
method are returned from the setup
. In the markup, we use the v-model
directive to create two-way data bindings
to the form inputs. Two-way data binding basically means that whenever the state is updated, the input fields will be updated accordingly, and when the input fields are updated, so will the state.
Last but not least, we have the @submit.prevent
event listener attached on the form element. Note that .prevent
, which was chained to the @submit
listener, is one of the event modifiers supported by Vue. In jQuery, we explicitly had to call e.preventDefault()
to prevent the default form behavior and stop it from being sent by the browser to the server, as we do it
using JavaScript.
Showing and Hiding Content
There are many use cases for showing specific markup only in certain situations, such as form validation messages, alerts or helper messages. Below you can see an example of how to toggle the visibility of a message paragraph in jQuery.
<div id="conditional-section">
<button id="messageBtn">Hide message</button>
<p id="message">Hello world</p>
</div>
<script type="text/javascript">
$(document).ready(() => {
const $btn = $("#messageBtn");
const $message = $("#message");
$btn.click(() => {
const isVisible = $message.is(":visible");
if (isVisible) {
$message.hide();
$btn.text("Show message");
} else {
$message.show();
$btn.text("Hide message");
}
});
});
</script>
Vue is a state-driven framework and this helps a lot with use cases such as this one, as we can easily render different content based on the state. For instance, as the code below shows, depending on the value of the isMessageVisible
ref,
the button’s text will either have a Hide
or Show
string. On top of that, we use the v-show
directive to control whether the message should be visible or not.
<div id="conditional-section">
<button
id="messageBtn"
@click="isMessageVisible = !isMessageVisible"
>
{{isMessageVisible ? 'Hide' : 'Show'}} message
</button>
<p v-show="isMessageVisible" id="message">Hello world</p>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const isMessageVisible = Vue.ref(true);
return {
isMessageVisible,
};
},
}).mount("#conditional-section");
</script>
This is another great example of the difference between jQuery and Vue. The code written with jQuery is very imperative, as we explicitly query for elements and update their text and visibility. On the other hand, Vue is declarative, and the DOM updates are automatically performed by Vue based on the state.
Besides the v-show
directive that toggles the display
style, Vue also provides the v-if
directive that can create and remove content from the DOM.
Rendering a List of Items
If we want to render a list of items, we usually need to generate the markup dynamically. We can loop through a list by either using one of the native array methods or with the each
method provided by jQuery. We can use the loop to generate
markup for each list item, and, after the loop, we just append the content to the desired HTML element.
<div id="list-container"></div>
<script type="text/javascript">
const fruits = ["apple", "banana", "orange"];
let content = [];
$.each(fruits, (idx, fruit) => {
content.push(`<li>${fruit}</li>`);
});
$("#list-container").append(`
<ul>
${content.join("\n")}
</ul>
`);
</script>
Vue is a bit more pragmatic when it comes to rendering lists, as it provides a directive called v-for
that can be used to loop through iterables and generate new content. All the markup is again defined directly in HTML. In the example below,
we have the v-for
directive on the li
element, as we want to create li
elements for each item in the fruits
array. Note that Vue requires us to provide a unique key
attribute that is
used for tracking changes and optimizing performance. In the setup
method, we just define and return the fruits
array.
<div id="list-container">
<ul>
<li v-for="(fruit, idx) of fruits" :key="idx">{{fruit}}</li>
</ul>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const fruits = ["apple", "banana", "orange"];
return {
fruits,
};
},
}).mount("#list-container");
</script>
Toggling Classes
I can’t even remember how many times I had to toggle classes with jQuery, but believe me, it was a lot. A good example of a feature that requires it, is tabs. If a user clicks on a tab, it should change to an active state, and if there was a previously active tab, it should be changed to a normal inactive state. Below you can see a very simple example in jQuery.
<style>
.tab {
background: none;
border: none;
}
.active {
background-color: aquamarine;
}
</style>
<div>
<button class="tab" id="tab-one">Tab 1</button>
<button class="tab" id="tab-two">Tab 2</button>
<button class="tab" id="tab-three">Tab 3</button>
</div>
<script type="text/javascript">
$(document).ready(() => {
$(".tab").click(e => {
// Remove current active classes
$(".tab.active").toggleClass("active");
const $btn = $(e.currentTarget);
// Turn on active class for the clicked tab
$btn.toggleClass("active");
});
});
</script>
Similarly to the handling events example, we query all tabs that contain the tab
class and attach a click
event listener to them. When one of the tabs is clicked, we first try to find a tab with the active
class
and then toggle it. Finally, we toggle the active
class on the tab that was just clicked. Now, let’s have a look at how to implement the same functionality with Vue.
<style>
.tab {
background: none;
border: none;
}
.active {
background-color: aquamarine;
}
</style>
<div id="toggling-classes">
<button
class="tab"
:class="{active: activeTabId === 'tab-one'}"
id="tab-one"
@click="activeTabId = 'tab-one'"
>
Tab 1
</button>
<button
class="tab"
:class="{active: activeTabId === 'tab-two'}"
id="tab-two"
@click="activeTabId = 'tab-two'"
>
Tab 2
</button>
<button
class="tab"
:class="{active: activeTabId === 'tab-three'}"
id="tab-three"
@click="activeTabId = 'tab-three'"
>
Tab 3
</button>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const activeTabId = Vue.ref(null);
return {
activeTabId,
};
},
}).mount("#toggling-classes");
</script>
The activeTabId
value is a reactive ref and is returned from the setup
method. Now, whenever the activeTabId
value changes, the DOM will be updated automatically. In the markup, we again have three buttons, and each
of them have the @click
directive attached. However, instead of passing a method as a handler, we pass a JavaScript expression that is used to update the reactive activeTabId
ref. Besides having the tab
class,
each button has a dynamic active
class that is applied conditionally when the expression activeTabId === 'value'
evaluates to true
.
To be honest, the Vue example actually involves many more lines of code than jQuery one, as we have to add dynamic classes and directives on each button separately. However, we can simplify the code for it by utilizing the v-for
loop and
creating the buttons dynamically. The example below provides the same result but is much cleaner and more concise. We define the tabs
array in the setup
method and then return it. What’s more, instead of using an id
to figure out which button should be active, we just use the array index.
<div id="toggling-classes">
<button
v-for="(tab, idx) of tabs"
:key="idx"
class="tab"
:class="{active: activeTabIdx === idx}"
@click="activeTabIdx = idx"
>
{{tab}}
</button>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const activeTabIdx = Vue.ref(null);
const tabs = ["Tab 1", "Tab 2", "Tab 3"];
return {
activeTabIdx,
tabs,
};
},
}).mount("#toggling-classes");
</script>
Performing API Requests
Web applications often need to perform API requests, for example, to fetch some data or submit a form. It’s also common to dynamically create content based on the data received from a server.
The jQuery example below utilizes the ajax
method to perform a GET
request to fetch a list of quotes. When the data is fetched successfully, we loop through it to dynamically create HTML markup. Finally, we query for the div
with quotes
id and append the dynamically generated content to it.
<div id="quotes"></div>
<script type="text/javascript">
$.ajax("https://type.fit/api/quotes", {
method: "GET",
success(data, textStatus, jqXHR) {
console.log("success", data);
let content = [];
JSON.parse(data)
.slice(0, 10)
.forEach(({ text, author }) => {
content.push(`
<li class="quote-list-item">
<div>
<span class="quote-text">${text}</span>
<br />
<span class="quote-author">${author}</span>
</div>
</li>
`);
});
$("#quotes").append(`
<ul class="quotes-list">
${content.join("\n")}
</ul>
`);
},
error(jqXHR, textStatus, error) {
console.log("error", jqXHR, textStatus, error);
},
});
</script>
Here’s the Vue implementation:
<div id="quotes">
<ul class="quotes-list">
<li
v-for="(quote, idx) of quotes"
:key="idx"
class="quote-list-item"
>
<div>
<span class="quote-text">{{quote.text}}</span>
<br />
<span class="quote-author">{{quote.author}}</span>
</div>
</li>
</ul>
</div>
<script type="text/javascript">
Vue.createApp({
setup() {
const quotes = Vue.ref([]);
Vue.onMounted(async () => {
try {
const response = await fetch(
"https://type.fit/api/quotes",
{
method: "get",
}
);
const result = await response.json();
quotes.value = result.slice(0, 10);
} catch (error) {
console.log("error", error);
}
});
return {
quotes,
};
},
}).mount("#quotes");
</script>
In contrast to the jQuery example where we only had an empty div with quotes
id, in Vue, we can define the markup for our quotes data directly in the HTML. We just need to use the v-for
directive to loop through the quotes. Initially,
the quotes
ref has an empty array as the initial value. However, when the quotes
ref is updated and populated with the data fetched from the server, Vue will re-render and update the DOM accordingly.
The API request to fetch the data is performed in the onMounted
lifecycle hook. Vue has multiple lifecycle hooks that are called at different lifecycle stages of the Vue app.* The onMounted
hook is executed when Vue finished
taking over the DOM and has rendered and committed updates to the DOM for the first time.
* You can read more about Vue lifecycle hooks here and here.
Summary
We have covered how to convert a few common functionalities from jQuery to Vue. jQuery served developers well for many years, but now there are solutions that can not only do the same things better but also provide more features. Let me note that we’ve covered only a gist of what can be done with Vue, and I highly recommend going through the official documentation, as there are many concepts we did not talk about, such as components, slots, computed properties, watchers and more.
You can find a full code example for this article in this GitHub repo.
Editor’s note: We know there are many reasons developers have for using either jQuery or Vue, or some combination of the two. Whatever your preference, Kendo UI has you covered! We will continue to offer support to both our jQuery and Vue component libraries (as well as React and Angular) for years to come.
This content originally appeared on Telerik Blogs and was authored by Thomas Findlay
Thomas Findlay | Sciencx (2022-04-21T08:34:00+00:00) How To Migrate From jQuery to Vue 3. Retrieved from https://www.scien.cx/2022/04/21/how-to-migrate-from-jquery-to-vue-3/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.