Xử lý tương tác dễ dàng với v-on

Một website hấp dẫn người xem phải có giao diện đẹp và có sự tương tác qua lại. Bạn hãy tưởng tượng một cô gái xinh đẹp nhưng hỏi gì cũng không biết, chạm vào không có phản ứng thì không gây cảm hứng cho người đối diện. Như vậy, tương tác là một yếu tố rất quan trọng, khéo léo bố trí các tương tác bạn vừa có thể khai thác được thông tin người dùng tối đa, vừa giúp cho họ tìm được những thông tin phù hợp, giữ người dùng ở lại với website lâu hơn và đồng nghĩa với lợi nhuận cao hơn.

Vue.js giúp bạn xử lý các sự kiện, tương tác với người dùng rất dễ dàng thông qua câu lệnh v-on. Câu lệnh này có thể kiểm soát tất cả các sự kiện có thể xảy ra với một phần tử HTML như nhấp chuột, gõ phím… Cuối bài viết chúng ta sẽ cùng nhau xây dựng một ứng dụng máy tính bỏ túi đơn giản như dưới đây:

1. Quản lý sự kiện với v-on

Sự kiện trong HTML là những gì xảy ra với các thẻ HTML, Vue.js là một bộ máy biên dịch mà kết quả cuối cùng là HTML, CSS và Javascript đơn thuần, do vậy Vue.js hoàn toàn có thể tương tác với các sự kiện của HTML. Có rất nhiều các sự kiện xảy ra khi người dùng làm một việc gì đó trên trang web:

  • Sự kiện tải trang web xảy ra khi người dùng nhập đường dẫn vào một trình duyệt web.
  • Sự kiện giá trị ô nhập liệu thay đổi khi người dùng thêm vào văn bản.
  • Một nút được nhấn cũng phát sinh sự kiện
  • Sự kiện một form đăng ký thông tin được gửi đi.

Trong framework Vue.js, để “lắng nghe” các sự kiện trên DOM (các thẻ HTML), bạn có thể sử dụng câu lệnh v-on với cú pháp:

v-on:tên_sự_kiện="mã_xử_lý_sự_kiện"

Có rất nhiều sự kiện trong HTML, chúng ta có thể tạm chia thành các nhóm sự kiện như sau:

  • Nhóm sự kiện liên quan đến trình duyệt như onload, onresize…
  • Nhóm sự kiện liên quan đến form: onsubmit, onchange, onblur…
  • Sự kiện liên quan đến bàn phím: onkeyup, onkeydown, onkeypress
  • Sự kiện liên quan đến chuột: onlick, onmouseover, onwheel…

Các sự kiện này khi sử dụng với v-on chúng ta bỏ đi tiền tố “on” ở đầu, ví dụ khi sử dụng v-on để quản lý sự kiện nhấp chuột chúng ta dùng v-on:click, khi sử dụng v-on với sự kiện gửi dữ liệu đi trong form (onsubmit) cú pháp là v-on:submit.

Mã xử lý sự kiện là mã viết bằng ngôn ngữ Javascript (hiện nay thường gọi là ECMAScript hay ES với phiên bản thường dùng hiện nay là ES5, ES6). Đoạn mã này có thể ở dạng inline, tức là nhồi toàn bộ code vào một dòng hoặc cũng có thể là lời gọi đến một phương thức.

1.1 Mã xử lý sự kiện inline

Đôi khi mã xử lý sự kiện rất đơn giản và không cần phải sử dụng lại, bạn có thể viết kiểu inline cho nhanh chóng. Ví dụ dưới đây chúng ta cùng xây dựng nút like cho bài viết, mỗi lần bấm nút like nó sẽ hiển thị số lượng like tăng thêm 1.

<!DOCTYPE html>
<html>
<head>
    <title>Quản lý sự kiện với v-on Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <div class="row">
            <div class="col-md-12">
                <h1>Quản lý sự kiện dễ dàng với v-on Vue.js</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <p>
                    Một website hấp dẫn người xem phải có giao diện đẹp và có sự tương tác qua lại. Bạn hãy tưởng tượng một cô gái xinh đẹp nhưng hỏi gì cũng không biết, chạm vào không có phản ứng thì không gây cảm hứng cho người đối diện. Như vậy, tương tác là một yếu tố rất quan trọng, khéo léo bố trí các tương tác bạn vừa có thể khai thác được thông tin người dùng tối đa, vừa giúp cho họ tìm được những thông tin phù hợp, giữ người dùng ở lại với website lâu hơn và đồng nghĩa với lợi nhuận cao hơn.
                </p>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <button type="button" class="btn btn-outline-primary" v-on:click="likes++">
                    <i class="far fa-thumbs-up"></i> Thích <span class="badge badge-pill badge-primary">{{ likes }}</span>
                </button>
                
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script src="https://use.fontawesome.com/releases/v5.0.9/js/all.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                likes: 9
            }
        })
    </script>
</body>
</html>

Trong ví dụ trên, chúng ta đã quản lý sự kiện nhấp vào nút “Thích” bằng đoạn mã:

<button type="button" class="btn btn-outline-primary" v-on:click="likes++">
    <i class="far fa-thumbs-up"></i> Thích <span class="badge badge-pill badge-primary">{{ likes }}</span>
</button>

Khi sự kiện nhấp chuột xảy ra, biến likes được cộng thêm 1, do việc cộng thêm 1 khá đơn giản chúng ta không cần dùng lời gọi phương thức mà đưa mã xử lý vào trong cùng câu lệnh v-on, do vậy có tên là inline. Giá trị biến likes được in ra bằng cú pháp biểu thức {{ }} mà chúng ta đã được làm quen trong Cú pháp câu lệnh trong Vue.js.

1.2 Sử dụng lời gọi phương thức trong code quản lý sự kiện

Code xử lý sự kiện trong v-on có giới hạn là một câu lệnh, như vậy chúng ta không thể đưa nhiều dòng lệnh inline vào v-on. Như vậy, nếu bạn muốn khi sự kiện xảy ra, thực hiện những công việc phức tạp thì giải pháp sử dụng lời gọi đến phương thức là lựa chọn duy nhất. Trong ví dụ ở trên, chúng ta muốn mỗi lần nhấp vào nút Thích phải cách nhau 10 giây nếu không sẽ hiển thị một thông báo.

<!DOCTYPE html>
<html>
<head>
    <title>Quản lý sự kiện với v-on Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <div class="row">
            <div class="col-md-12">
                <h1>Quản lý sự kiện dễ dàng với v-on Vue.js</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <p>
                    Một website hấp dẫn người xem phải có giao diện đẹp và có sự tương tác qua lại. Bạn hãy tưởng tượng một cô gái xinh đẹp nhưng hỏi gì cũng không biết, chạm vào không có phản ứng thì không gây cảm hứng cho người đối diện. Như vậy, tương tác là một yếu tố rất quan trọng, khéo léo bố trí các tương tác bạn vừa có thể khai thác được thông tin người dùng tối đa, vừa giúp cho họ tìm được những thông tin phù hợp, giữ người dùng ở lại với website lâu hơn và đồng nghĩa với lợi nhuận cao hơn.
                </p>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <div class="alert alert-danger" role="alert" v-if="alert">
                    Chỉ được thêm like sau 10 giây
                </div>
                <button type="button" class="btn btn-outline-primary" v-on:click="like">
                    <i class="far fa-thumbs-up"></i> Thích <span class="badge badge-pill badge-primary">{{ likes }}</span>
                </button>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script src="https://use.fontawesome.com/releases/v5.0.9/js/all.js"></script>
    <script src="https://momentjs.com/downloads/moment.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                likes: 9,
                lastClickTime: null,
                alert: false
            },
            methods: {
                like: function () {
                    if (this.lastClickTime === null || moment().diff(moment(this.lastClickTime), 'seconds') > 10) {
                        this.likes ++;
                        this.lastClickTime = moment().format();
                        this.alert = false
                    } else {
                        this.alert = true;
                    }
                }
            }
        })
    </script>
</body>
</html>

Trong đoạn code trên có một số vấn đề có lẽ bạn sẽ chưa rõ hiểu rõ nhưng đừng quá lo lắng vì có một số kiến thức chúng ta sẽ được làm quen ở các phần tiếp theo. Trong khuôn khổ bài viết sẽ cố gắng trình bày các thông tin cơ bản nhất.

Thứ nhất, đoạn mã v-on:click ở phần 1.1 đã được thay thế bằng một lời gọi phương thức like() thay vì sử dụng câu lệnh inline.

<div class="alert alert-danger" role="alert" v-if="alert">
    Chỉ được thêm like sau 10 giây
</div>
<button type="button" class="btn btn-outline-primary" v-on:click="like">
    <i class="far fa-thumbs-up"></i> Thích <span class="badge badge-pill badge-primary">{{ likes }}</span>
</button>

Thông báo “Chỉ được thêm like sau 10 giây” có sử dụng cú pháp điều kiện v-if, nếu biến alert có giá trị là true thì thông báo này sẽ được hiển thị.

Thứ hai, chúng ta thấy xuất hiện một phương thức like() được khai báo trong thuộc tính methods của Vue instance. Vậy Vue instance là gì, thuộc tính methods của Vue sử dụng như thế nào? Tạm thời, khi cần một phương thức như trong Javascript đơn thuần, chúng ta sẽ khai báo trong thuộc tính methods của Vue, cụ thể cách dùng thế nào sẽ có một bài viết riêng cho vấn đề này.

<script type="text/javascript">
    new Vue({
        el: '#app',
        data: {
            likes: 9,
            lastClickTime: null,
            alert: false
        },
        methods: {
            like: function () {
                if (this.lastClickTime === null || moment().diff(moment(this.lastClickTime), 'seconds') > 10) {
                    this.likes ++;
                    this.lastClickTime = moment().format();
                    this.alert = false
                } else {
                    this.alert = true;
                }
            }
        }
    })
</script>

Khi tham chiếu đến các biến được khai báo trong thuộc tính data của Vue, chúng ta sử dụng this. Chúng ta có 3 biến likes để lưu giữ số like hiện tại, lastClickTime chứa thời gian nhấp chuột được like sau cùng, alert là true sẽ hiển thị thông báo, mặc định là false.

Thứ ba, chúng ta sử dụng thêm một thư viện ngoài là moment.js, đây là một thư viện rất mạnh về xử lý thời gian nó giống như thư viện Carbon chúng ta hay dùng trong Laravel vậy.

1.3 Viết tắt khi sử dụng v-on

Vue.js cho phép bạn viết tắt cú pháp v-on:tên_sự_kiện thành :tên_sự_kiện. Ví dụ

<button type="button" class="btn btn-outline-primary" v-on:click="like">

có thể viết lại thành

<button type="button" class="btn btn-outline-primary" @click="like">

Cách viết này giúp bạn đỡ phải gõ code nhiều và code nhìn trông cũng đỡ rối rắm hơn, nhất là với các dự án sử dụng framework Vue.js có số lượng code lớn.

Chú ý, khi mới làm quen với Vue.js có thể bạn sẽ nhầm sang cách viết tắt :click do v-bind:thuộc_tính được viết tắt thành :thuộc_tính.

2. Thay đổi sự kiện gốc

Nếu bạn đã làm việc nhiều với Javascript hẳn bạn sẽ biết phương thức preventDefault() của đối tượng event. Phương thức này sẽ hủy bỏ sự kiện nếu có thể, tức là hành động mặc định của phần tử HTML sẽ không xảy ra. Chúng ta cùng xem ví dụ sau, thẻ <a> là một liên kết, khi bạn nhấp chuột vào liên kết này trình duyệt sẽ đưa bạn đến trang web có URL được thiết lập trong thẻ <a> đó. Tuy nhiên, vì lý do nào đó chúng ta muốn khi nhấp vào liên kết này sẽ hiển thị một cảnh báo thay vì chuyển sang trang, preventDefault() sẽ giúp bạn.

Với Vue.js bạn hoàn toàn có thể sử dụng các phương thức kiểu như preventDefault(), stopPropagation()… bên trong các sự kiện tuy nhiên sẽ tốt hơn nếu v-on hỗ trợ cú pháp sử dụng các tính năng tương tự, nó giúp cho tường minh và hợp logic hơn. Rất may, Vue.js cũng đã quan tâm đến điều này và nó đưa ra cú pháp để thực hiện thay đổi sự kiện như sau v-on:tên_sự_kiện.phương_thức_thay_đổi_sự_kiện. Trong Vue.js có các phương thức để thay đổi sự kiện gốc như sau:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once

Ví dụ thuần Javascript ở trên có thể được viết lại như sau trong Vue.js

<!DOCTYPE html>
<html>
<head>
    <title>Quản lý sự kiện với v-on Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div class="container" id="app">
        <div class="row">
            <div class="col-md-12">
                <a href="https://allaravel.com/tutorials/vuejs-framework/khoa-hoc-vue-js-2-mien-phi/" @click.prevent="courseClick">Khóa học Vue.js miễn phí</a>
            </div>
            <div class="col-md-12" v-if="show">
                <div class="list-group">
                    <a :href="tut.url" class="list-group-item" v-for="tut in tutorials" target="_blank">{{ tut.title }}</a>
                </div>
            </div>
            <div class="col-md-12">
                <a href="https://allaravel.com/tutorials/vuejs-framework/khoa-hoc-vue-js-2-mien-phi/" target="_blank">Khóa học Vue.js miễn phí</a>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <p>Thay đổi sự kiện gốc trong Vue.js, cũng là thẻ a bạn hãy nhấp thử hai liên kết trên để trải nghiệm</p>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                show: false,
                tutorials: [
                    {title: '1.1 Giới thiệu framework Vue.js', url: 'https://allaravel.com/tutorials/vuejs-framework/gioi-thieu-framework-vue-js/'},
                    {title: '1.2 Cài đặt môi trường Vue.js', url: 'https://allaravel.com/tutorials/vuejs-framework/cai-dat-moi-truong-vue-js/'},
                    {title: '1.3 Công cụ sử dụng trong phát triển Vue.js', url: 'https://allaravel.com/tutorials/vuejs-framework/cong-cu-su-dung-trong-phat-trien-vue-js/'},
                    {title: '2.1 Cú pháp câu lệnh', url: 'https://allaravel.com/tutorials/vuejs-framework/mau-cu-phap-cau-lenh-trong-vue-js/'},
                    {title: '2.2 Cú pháp điều kiện v-if, v-show', url: 'https://allaravel.com/tutorials/vuejs-framework/cau-lenh-dieu-kien-v-if-va-v-show/'},
                ]
            },
            methods: {
                courseClick: function () {
                    this.show = !this.show;
                }
            }
        })
    </script>
</body>
</html>

Trong ví dụ này, khi quản lý sự kiện click vào thẻ a, chúng ta đã sử dụng phương thức ngăn chặn sự kiện xảy ra .prevent.

<a href="https://allaravel.com/tutorials/vuejs-framework/khoa-hoc-vue-js-2-mien-phi/" @click.prevent="courseClick">Khóa học Vue.js miễn phí</a>

3. Thay đổi hoạt động bàn phím, chuột

Trong ứng dụng web của bạn, đôi bạn muốn thay đổi cách hành xử khi một phím được nhấn. Ví dụ, trên một form khi bạn nhấn Enter thì dữ liệu form sẽ được gửi đi (submit) hoặc khi bạn nhấn PageUp, PageDown trình duyệt sẽ cuộn cả nội dung trang nhưng bạn lại muốn chỉ cuộn nội dung phần danh sách ảnh trong trang… Vue.js cho phép bạn thay đổi cách hành xử các phím trên bàn phím hoặc chuột được nhấn.

Cú pháp quản lý hoạt động của bàn phím như sau:

v-on:tên_sự_kiện.mã_phím_hoặc_tên_phím="mã_xử_lý_sự_kiện"

Ví dụ:

<input type="button" v-on:keyup.13="submit">

Trong ví dụ trên 13 là mã của phím enter, khi bấm enter form sẽ được submit. Ngoài ra chúng ta có thể sử dụng tên phím thay cho mã phím:

<input type="button" v-on:keyup.enter="submit">

Danh sách một số tên phím được định nghĩa sẵn:

  • .enter
  • .tab
  • .delete
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift

Với các phím của chuột, chúng ta có danh sách sau:

  • .left
  • .right
  • .middle

Chúng ta có thể tổ hợp các phím với nhau, ví dụ khi ấn Ctrl + F1 trên phần tử HTML nào đó sẽ hiển thị hướng dẫn về phần tử đó.

<p v-on:keyup.ctrl.112="showHelp">

112 là mã của phím F1. Trong ví dụ này, nếu bạn nhấn tổ hợp nhiều phím mà có chứa Ctrl + F1 thì v-on:keyup vẫn hoạt động, để có thể quản lý chính xác phím hoặc tổ hợp phím sử dụng .exact.

<p v-on:keyup.exact.ctrl.112="showHelp">

4. Bài tập

Các kiến thức quản lý sự kiện với v-on trong Vue.js là khá nhiều nhưng cũng rất đơn giản. Bạn hãy thực hành thật nhiều các ví dụ trong bài và hoàn thành bài tập sau đây, tôi tin chắc bạn sẽ nắm vững những gì được trình bày trong bài viết này. Phần bài tập tiếp theo sẽ cần vận dụng khá nhiều các kiến thức khác nhau, hãy cố gắng hoàn thành nhé.

Viết một ứng dụng web dạng máy tính bỏ túi với tính năng cộng trừ nhân chia cơ bản.

Phần 1: Xây dựng giao diện

Giao diện được xây dựng dựa trên framework CSS Bootstrap dạng lưới, mỗi nút trên máy tính bỏ túi là một thẻ div có kích thước bằng 1 ô trong lưới 12 ô. Bạn nên tìm hiểu về framework Bootstrap vì hiện nay có rất nhiều các giao diện web được xây dựng dựa trên nó.

Phần 2: Quản lý sự kiện khi bấm thành phần của số.

<div class="col-md-1 col-3 border btn" @click="inputNumber('8')">8</div>

Chúng ta xây dựng một phương thức inputNumber() để nhập các thành phần của một số bao gồm các số từ 0 đến 9 và dấu chấm (.) cho các số thập phân. Đầu vào của phương thức inputNumber() chính là thành phần của số cần tính toán.

inputNumber: function(partOfNumber) {
    if (partOfNumber == '.' && this.resultString.includes('.')) {
        return;
    } else if (this.resultString == '0') {
        this.resultString = partOfNumber;
        this.realValue = partOfNumber;
    } else {
        this.realValue += partOfNumber;
        this.resultString = this.realValue;
    }
}

Nếu số hiện tại đã có phần thập phân thì bấm vào nút thập phân sẽ không thêm dấu thập phân nữa. Khi bấm các nút số thì nó thêm số đó vào chuỗi số.

Phần 3: Quản lý sự kiện khi bấm các nút liên quan đến tính toán

Chúng ta có một số toán tử cơ bản trong máy tính bỏ túi là:

  • + cộng hai số
  • – trừ hai số
  • x nhân
  • / chia
  • i đảo dấu
  • % tính phần trăm
  • = tính toán kết quả cuối cùng

Phương thức calculate() sẽ thực hiện tính toán. Trong phương thức này, chúng ta sử dụng hàm eval() của Javascript để thực hiện tính toán một biểu thức ở dạng chuỗi.

calculate: function(operator) {
    if (operator == '=' && this.currentOperator != '') {
        this.expression += this.resultString;
        this.resultString = eval(this.expression).toString();
        this.realValue = '';
        this.currentOperator = '';
        this.expression = this.resultString;
    } else if (operator == '%') {
        this.expression = '';
        this.resultString = (this.resultString/100).toString();
        this.realValue = this.resultString;
    } else if (operator == 'i') {
        if (this.resultString == 0) {
            return;
        }
        if (this.resultString[0] == '-') {
            this.resultString = this.resultString.substr(1);
        } else {
            this.resultString = '-' + this.resultString;
            this.realValue = this.resultString;
        }
    } else {
        this.currentOperator = operator;
        this.expression += this.realValue;
        this.resultString = eval(this.expression).toString();
        this.expression = this.resultString;
        this.expression += operator;
        this.realValue = '';
    }
}

Phần 4: Xây dựng nút xóa trên máy tính bỏ túi.

Quản lý sự kiện khi click vào nút C (clear).

<div class="col-md-1 col-3 offset-md-4 btn btn-danger" @click="clearScreen">C</div>

và phương thức clearScreen()

clearScreen: function() {
    if (this.resultString != '0') {
        this.expression = '';
        this.resultString = '0';
        this.realValue = '';
    }
}

Phần 5: Nâng cao

Bài tập này có hai phần có thể mở rộng:

  • Xây dựng máy tính bỏ túi khoa học có thể tính toán sin, cos, giải các phương trình cơ bản…
  • Nâng cao khả năng nhập bằng bàn phím.

5. Kết luận

Qua bài viết chúng ta đã nắm bắt được cách quản lý sự kiện trong Vue.js với câu lệnh v-on. Xây dựng ứng dụng bằng framework Vue.js thật đơn giản, tính logic chặt chẽ, code gọn gàng, khoa học. Bạn đã cùng với chúng tôi đi được gần hết các phần câu lệnh cơ bản, chỉ với những kiến thức đơn giản này, bạn đã có thể xây dựng được những ứng dụng nhỏ hữu ích. Bạn bắt đầu thấy mê Vue.js rồi phải không, rất nhiều bài viết của Khóa học Vue.js miễn phí sẽ được xuất bản trong thời gian tới. Hãy đón xem và có bất kỳ câu hỏi nào đừng ngại, comment ở cuối bài nhé.

Add Comment