Home >Web Front-end >JS Tutorial >How to Replace jQuery with Vue
Say goodbye to jQuery and embrace Vue.js: build a simpler and more efficient web application
Want to learn Vue.js from scratch? Join SitePoint Premium now to get a complete collection of Vue.js books covering Vue.js basics, project practices, tips and more for just $14.99 per month!
Many developers still rely on jQuery when building simple applications. While sometimes you only need to add a small amount of interactivity to your page, using JavaScript frameworks seems too complicated - extra code volume, boilerplate code, build tools and module packers, and more. Introducing jQuery from CDN seems like a breeze to choose.
This article is intended to convince you that even for relatively simple projects, using Vue.js (hereinafter referred to as Vue) does not require any effort, but will help you write better code faster. We will take a simple example as an example to encode using jQuery and Vue respectively, and gradually demonstrate its differences.
This article will build a simple online invoice using the open source template provided by Sparksuite. Hopefully this is more innovative than another to-do list and is complex enough to demonstrate the advantages of using Vue while being easy to understand.
We will make it interactive by providing item, unit price, and quantity inputs and automatically recalculate the "Price" column when one of the values changes. We will also add a button to insert new blank rows into the invoice, as well as a "Total" field that will be automatically updated as we edit the data.
I have modified the template so that the HTML for a single (empty) row looks like this:
<code class="language-html"><tr> class="item"> <td><input type="text" v-model="item.description"></td> <td><input type="number" v-model="item.price"></td> <td><input type="number" v-model="item.quantity"></td> <td> <pre class="brush:php;toolbar:false"><code class="language-javascript">$('table').on('mouseup keyup', 'input[type=number]', calculateTotals);</code>.00
First, let's see how to implement this function using jQuery.
<code class="language-javascript">function calculateTotals() { const subtotals = $('.item').map((idx, val) => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v) => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); }</code>
We attach the listener to the table itself, and when the "Unit Cost" or "Quantity" value changes, the calculatedTotals function will be executed:
<code class="language-javascript">function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; }</code>
This function looks up all the item rows in the table and loops through them, passing each row to the calculateSubtotal function, and then adding the results. Then, insert this total into the relevant location of the invoice.
<code class="language-html"><tr> class="item"> <td><input type="text" v-model="item.description"></td> <td><input type="number" v-model="item.price"></td> <td><input type="number" v-model="item.quantity"></td> <td> <pre class="brush:php;toolbar:false"><code class="language-javascript">$('table').on('mouseup keyup', 'input[type=number]', calculateTotals);</code>.00
In the above code, we get a reference to all input elements in the line and multiply the second and third ones to get a subtotal. Then, insert this value into the last cell in the row.
<code class="language-javascript">function calculateTotals() { const subtotals = $('.item').map((idx, val) => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v) => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); }</code>
We also have a helper function to ensure that both subtotal and total are formatted into two decimals and prefixed with currency symbols.
<code class="language-javascript">function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; }</code>
Finally, we have a click handler for the "Add Row" button. What we do here is select the last project row and create a copy. The input to the cloned row is set to the default value and insert it as the new last row. We can also facilitate users and set focus to the first input so they can start typing.
The following is the complete jQuery demonstration: CodePen link
Disadvantages of jQuery
So, what's wrong with this code? Or, where can we improve it?
You may have heard of some newer libraries like Vue and React claiming to be declarative rather than imperative. Of course, looking at this jQuery code, most of the code is a list of instructions on how to operate the DOM. The purpose of each part of the code—"what"—is often difficult to distinguish through the details of "how to do it". Of course, we can clarify the intent of the code by breaking it down into well-named functions, but this code still takes some effort to re-understand after a while.
Another problem with this kind of code is that we save the application state in the DOM itself. Information about the ordering project exists only as part of the HTML that constitutes the UI. This doesn't seem like a big problem when we display information in only one location, but once we start needing to display the same data in multiple locations in the application, making sure each section remains in sync becomes increasingly complex. There is no single source of fact.
While nothing can stop us from not saving state outside of the DOM and avoiding these problems, libraries like Vue provide the functionality and structure that facilitates the creation of good architecture and write cleaner, more modular code.
So, how do we use Vue to reproduce this feature?
As I mentioned earlier, Vue does not require us to use a module packer, a translator, or select a single file component (.vue file) to get started. Like jQuery, we can simply include libraries from CDN. Let's start with replacing script tags:
<code class="language-javascript">function formatAsCurrency(amount) { return `$${Number(amount).toFixed(2)}`; }</code>
Next, we need to create a new Vue instance:
<code class="language-javascript">$('.btn-add-row').on('click', () => { const $lastRow = $('.item:last'); const $newRow = $lastRow.clone(); $newRow.find('input').val(''); $newRow.find('td:last').text('<pre class="brush:php;toolbar:false"><code class="language-html"></code>.00'); $newRow.insertAfter($lastRow); $newRow.find('input:first').focus(); });
Here we just need to provide the el option, which is a selector (just like we do with jQuery) to identify which part of the document we want Vue to manage.
We can have Vue take care of anything starting from the entire page (for example, for a single page application) or a single
Data
Let's also add the relevant data from three example lines to our Vue instance:
<code class="language-html"><tr> class="item"> <td><input type="text" v-model="item.description"></td> <td><input type="number" v-model="item.price"></td> <td><input type="number" v-model="item.quantity"></td> <td> <pre class="brush:php;toolbar:false"><code class="language-javascript">$('table').on('mouseup keyup', 'input[type=number]', calculateTotals);</code>.00
data attribute is where we store the application state. This includes not only any data we want the application to use, but also information about the UI status (e.g., the currently active part of the tab group, or whether the accordion is expanded or collapsed).
Vue encourages us to separate the state of the application from its representation (i.e., the DOM) and concentrate in one place-a single source of fact.
Modify template
Now let's set our template to display items from our data object. Since we have told Vue that we want it to control the table, we can use its template syntax in HTML to tell Vue how to render and manipulate it.
Using the v-for property, we can render a piece of HTML for each item in the items array:
<code class="language-javascript">function calculateTotals() { const subtotals = $('.item').map((idx, val) => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v) => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); }</code>
Vue will repeat this tag for each element we pass to the array (or object) constructed by v-for, allowing us to reference each element in the loop - in this case item. Since Vue is observing all properties of the data object, it will dynamically rerender the markup as the items content changes. We just need to add or delete items to the application status and Vue will be responsible for updating the UI.
We also need to add an input box so that the user can fill in the item description, unit price and quantity:
<code class="language-javascript">function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; }</code>
Here, we use the v-model property to set the two-way binding between the input and the properties on the project model. This means that any changes to the input will update the corresponding properties on the project model and vice versa.
In the last cell, we use double braces {{ }} to output some text. We can use any valid JavaScript expression inside braces, so we multiply the two project properties and output the result. Similarly, since Vue is observing our data model, changes to either property will cause the expression to be automatically recalculated.
Events and methods
Now we have set up the template to render our items collection, but how do we add new lines? Since Vue will render anything in items, to render empty lines, we just need to push the object with any default value we want into the items array.
To create functions that can be accessed in the template, we need to pass them to our Vue instance as properties of the methods object:
<code class="language-javascript">function formatAsCurrency(amount) { return `$${Number(amount).toFixed(2)}`; }</code>
Let's define an addRow method which we can call to add a new item to our items array:
<code class="language-javascript">$('.btn-add-row').on('click', () => { const $lastRow = $('.item:last'); const $newRow = $lastRow.clone(); $newRow.find('input').val(''); $newRow.find('td:last').text('<pre class="brush:php;toolbar:false"><code class="language-html"></code>.00'); $newRow.insertAfter($lastRow); $newRow.find('input:first').focus(); });
Note that any method we create will be automatically bound to the Vue instance itself, so we can access properties and other methods in the data object as properties of this.
So, now we have a method, how do we call it when clicking the "Add Row" button? The syntax for adding event listeners to elements in a template is v-on:event-name:
<code class="language-javascript">const app = new Vue({ el: 'table' });</code>
Vue also provides us with a shortcut so that we can use @ instead of v-on:, like I did in the code above. For handlers, we can specify any method in the Vue instance.
Computing properties
Now we just need to display the total at the bottom of the invoice. We can probably do this in the template itself: As I mentioned earlier, Vue allows us to place any JavaScript statement between curly braces. However, it is better to keep anything beyond the very basic logic outside the template; if we separate the logic, it is clearer and easier to test.
We can use another method for this, but I think the computed properties are more appropriate. Similar to the creation method, we pass a computed object containing functions to our Vue instance, and we want the result of these functions to be used in the template:
<code class="language-html"><tr> class="item"> <td><input type="text" v-model="item.description"></td> <td><input type="number" v-model="item.price"></td> <td><input type="number" v-model="item.quantity"></td> <td> <pre class="brush:php;toolbar:false"><code class="language-javascript">$('table').on('mouseup keyup', 'input[type=number]', calculateTotals);</code>.00
Now we can reference this computed property in the template:
<code class="language-javascript">function calculateTotals() { const subtotals = $('.item').map((idx, val) => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v) => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); }</code>
As you may have noticed, computed properties can be treated like data; we don't have to call them in brackets. But there is another benefit to using computed properties: Vue is smart enough to cache the return value and will recalculate the function only if one of the data properties it depends on changes.
If we use methods to calculate the total, the calculation will be performed every time the template is re-rendered. Because we are using computed properties, the total will be recalculated only if the quantity or price field of the item changes.
Filter
You may have noticed a small error in our implementation. Although unit cost is an integer, our total and subtotals are not displayed when it is displayed. What we really want is to always display these numbers as two decimal places.
Rather than modifying the code that calculates subtotals and calculates totals, Vue provides us with a good way to handle common formatting tasks like this: filters.
As you may have guessed, to create a filter, we simply pass an object with that key to our Vue instance:
<code class="language-javascript">function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; }</code>
Here we create a very simple filter called currency which calls value.toFixed(2) and returns the result. We can apply it to any output in the template as follows:
<code class="language-javascript">function formatAsCurrency(amount) { return `$${Number(amount).toFixed(2)}`; }</code>
The following is the full Vue demo: CodePen link
Compare the two versions of the code side by side, and several aspects of the Vue application are prominent:
The sizes (in KB) of the two libraries are almost the same. Of course, you can streamline jQuery with a custom build, but even for relatively simple projects like our invoice example, I think the ease of development and the readability of the code justifies this difference.
Vue can do a lot of things that we haven't introduced here. Its advantage is that it allows you to create modular, reusable UI components that can be combined into complex frontend applications. If you are interested in getting to know Vue in depth, I suggest you check out Getting Up and Running with the Vue.js 2.0 Framework.
jQuery is a fast, compact and feature-rich JavaScript library. It makes HTML document traversal and manipulation, event processing, and animations easier, and its easy-to-use API can run in a variety of browsers. Vue.js, on the other hand, is a progressive JavaScript framework for building user interfaces. Unlike other overall frameworks, Vue's design has incremental adoptability from the very beginning. The core library focuses only on view layers, is easy to get started and integrates with other libraries or existing projects.
While jQuery has been a reliable tool for many years, Vue.js provides a more modern and comprehensive way to build web applications. Vue.js is component-based, which promotes reusability and maintainability. It also has a stronger ecosystem with tools such as state management, routing, etc. Additionally, Vue.js has a virtual DOM that can improve performance in some cases.
Converting jQuery code to Vue.js requires understanding of the equivalent Vue.js methods and properties of jQuery functions. For example, you will use Vue's mounted() lifecycle hook instead of jQuery's $(document).ready(). Similarly, you will use Vue's axios or fetch instead of jQuery's $.ajax() for HTTP requests.
While technically can use both jQuery and Vue.js, this is not usually recommended. Mixing the two can lead to code confusion and potential conflicts, as both libraries try to manage the DOM on their own terms. It is best to use one of them completely.
In jQuery, you usually attach an event listener to an element using methods such as .click(), .on(), or .bind(). In Vue.js, you use the v-on directive (or its abbreviation @) to listen for DOM events and run some JavaScript when triggered.
jQuery does not have built-in data binding. You manually select an element and update its contents. On the contrary, Vue.js has a powerful data binding system. You can use the v-model directive to create two-way data bindings on form input, textarea, and select elements.
jQuery has built-in animation methods, such as .fadeIn(), .slideUp(), etc. Vue.js, on the other hand, provides conversion components that allow greater flexibility when animate elements into and out of the DOM.
In jQuery, you usually use the $.ajax() method to make HTTP requests. Vue.js does not have this method built in, but you can use libraries like modern APIs (like fetch) or axios to make HTTP requests.
jQuery does not have a built-in reactive system. When your data changes, you manually update the DOM. Vue.js, on the other hand, has a reactive data system. The view is automatically updated when you change the data.
Many jQuery plugins can be replaced with Vue.js components. Vue.js has a rich ecosystem that provides thousands of open source components available. You can also create your own custom components. This improves the reusability and maintainability of the code.
Please note that I have rewritten the output according to your requirements and retained the original format and location of all pictures. Since I don't have access to CodePen, I can't provide the actual CodePen link, please create and replace the "[CodePen link]" placeholder yourself.
The above is the detailed content of How to Replace jQuery with Vue. For more information, please follow other related articles on the PHP Chinese website!