VueJS: Xử lý sự kiện

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Lắng nghe sự kiện

Chúng ta có thể dùng directive v-on để lắng nghe các sự kiện DOM và thực thi JavaScript khi những sự kiện này được kích hoạt. Ví dụ:

<!DOCTYPE html>
<html>
<head>
    <script src="http://192.168.1.22:8098"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body style="font-size: 30px">
<section id="app-1">
    <button @click="counter += 1">Đếm số</button>
    <p>{{counter}}</p>
</section>
<script>
    new Vue({
        el:'#app-1',
        data:{
            counter:0
        }
    });
</script>
</body>
</html>

Demo »

Phương thức xử lý sự kiện

Trong thực tế, logic để xử lý sự kiện thường phức tạp hơn, vì thế chứa JavaScript trực tiếp trong giá trị của thuộc tính v-on như trên là không khả thi. Đó là lý do v-on cũng có thể nhận tên của một phương thức mà bạn muốn gọi. Ví dụ:

<!DOCTYPE html>
<html>
<head>
    <script src="http://192.168.1.22:8098"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body style="font-size: 30px">
<section id="app-2">
    <button @click="welcome">Click => Chào mừng</button>
    <!-- welcome là tên phương thức ta muốn gọi -->
</section>
<script>
    new Vue({
        el:'#app-2',
        data:{
            name:'Larave-VueJS'
        },
        //Đối tượng 'methods' là nơi định nghĩa các phương thức
        methods:{
            welcome: function(event){
                //this ở đây là đối tượng Vue
                alert('Xin chào ' + this.name + '!');
                //event là sự kiện DOM native
                if(event){
                    alert(event.target.tagName);
                }
            }
        }

    });
</script>
</body>
</html>

Demo »

Gọi phương thức inline

Thay vì bind trực tiếp tên phương thức, ta cũng có thể gọi phương thức trong một câu lệnh JavaScript:

<!DOCTYPE html>
<html>
<head>
    <script src="http://192.168.1.22:8098"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body style="font-size: 30px">
<section id="app-3">
    <button @click="welcome('Laravel')">Laravel</button>
    <button @click="welcome('VueJS')">VueJS</button>
</section>
<script>
    new Vue({
        el:'#app-3',
        methods:{
            welcome: function(event){
                alert('Xin chào ' + event);
            }
        }
    });
</script>
</body>
</html>

Demo »

Đôi khi chúng ta cũng muốn truy xuất đến sự kiện DOM ban đầu từ câu lệnh JavaScript inline. Bạn có thể truyền sự kiện DOM vào phương thức thông qua biến $event:

<!DOCTYPE html>
<html>
<head>
    <script src="http://192.168.1.22:8098"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body style="font-size: 30px">
<section id="app-4">
    <button @click="warn('Form chưa submit được', $event)">Submit</button>
</section>
<script>
    new Vue({
        el:'#app-4',
        methods:{
            welcome: function(event){
                alert('Xin chào ' + event);
            },

            warn: function(alert1, event){
                if(event) event.preventDefault();
                alert(alert1)
            }

        }
    });
</script>
</body>
</html>

Demo »

Event modifier

Trong rất nhiều trường hợp, chúng ta cần gọi event.preventDefault() hoặc event.stopPropagation() bên trong một phương thức xử lý sự kiện. Tuy việc này không có gì khó, sẽ tốt hơn nếu các phương thức chỉ phải tập trung giải quyết logic dữ liệu thay vì cáng đáng các sự kiện DOM.

Để giải quyết vấn đề này, Vue cung cấp các event modifier cho v-onEvent modfier là một hậu tố (postfix) cho directive, được biểu thị bằng một dấu chấm.

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
<!--
  sự kiện click sẽ không được propagate (lan truyền)
  điều này tương đương với event.stopPropagation()
-->
<a v-on:click.stop="doThis"></a>

<!--
  sự kiện submit sẽ không reload trang
  điều này tương đương với event.preventDefault()
-->
<form v-on:submit.prevent="onSubmit"></form>

<!-- ta có thể nối modifier với nhau -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- chỉ có modifier, không có phương thức xử lí -->
<form v-on:submit.prevent></form>

<!--
  dùng "capture mode" khi thêm event listener
  nghĩa là một sự kiện xảy ra với một phần tử bên trong sẽ được xử lý ở đây
  trước khi được xử lý bởi phần tử đó
  đọc thêm về event capturing: https://javascript.info/bubbling-and-capturing#capturing
-->
<div v-on:click.capture="doThis">...</div>

<!--
  chỉ kích hoạt phương thức xử lý nếu event.target là chính phần tử được click,
  chứ không phải là một phần tử con
-->
<div v-on:click.self="doThat">...</div>

Khi sử dụng nhiều modifier cùng lúc, thứ tự nối là rất quan trọng, vì code sẽ được tạo ra theo đúng thứ tự đó. Ví dụ, `@click.prevent.self sẽ ngăn **toàn bộ click** còn @click.self.prevent` chỉ ngăn các click trên chính phần tử đang được nhắc đến.

Từ phiên bản 2.1.4 trở đi

<!-- sự kiện click sẽ chỉ được kích hoạt tối đa một lần -->

<a v-on:click.once="donateKidney"></a>

Không như các modifier khác, vốn chỉ dùng được cho các sự kiện DOM native, modifier .once cũng có thể dùng cho các sự kiện component. Nếu bạn chưa đọc về component, có thể bỏ qua và quay lại sau.

Từ phiên bản 2.3.0 trở đi

Vue cũng cung cấp modifier .passive, tương ứng với tùy chọn passive cho addEventListener.

<!-- 
hành vi mặc định của sự kiện scroll (cuộn trang) sẽ xảy ra 
ngay lập tức, thay vì đợi `onScroll` hoàn tất.
-->
<div v-on:scroll.passive="onScroll">...</div>

Modifier .passive đặc biệt hữu ích để cải thiện hiệu năng của ứng dụng trên các thiết bị di động.

Đừng dùng .passive và .prevent cùng nhau, vì .prevent sẽ không có hiệu lực, và trình duyệt có thể sẽ bật cảnh báo. Nên nhớ rằng .passive thông báo cho trình duyệt biết rằng bạn không muốn ngăn chặn hành vi mặc định của sự kiện.

Key modifier

Khi lắng nghe các sự kiện bàn phím (keyboard event), chúng ta thường phải kiểm tra mã phím (key code). Vue hỗ trợ thêm key modifier (modifer cho mã phím) cho v-on trong các trường hợp này:

<!-- chỉ gọi vm.submit() khi keyCode là 13 (phím Enter) -->

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

Tất nhiên nếu phải nhớ toàn bộ các mã phím thì rất mệt mỏi, nên Vue cung cấp alias (bí danh) cho các phím thông dụng nhất:

<!-- như trên -->

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

<!-- cũng hoạt động với cách viết tắt của v-on -->

<input @keyup.enter="submit">

Sau đây là danh sách đầy đủ của các key modifier:

  • .enter
  • .tab
  • .delete (dùng cho cả hai phím “Delete” và “←”)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

Bạn cũng có thể tự định nghĩa alias cho key modifier bằng object toàn cục config.keyCodes. Ví dụ:

// cho phép sử dụng v-on:keyup.f1

Vue.config.keyCodes.f1 = 112

Key modifier tự động

2.5.0+

Bạn cũng có thể sử dụng bất kỳ tên phím hợp lệ nào để làm modifier bằng cách chuyển sang kebab-case:

<input @keyup.page-down="onPageDown">

Trong ví dụ trên, hàm onPageDown chỉ được gọi nếu $event.key === 'PageDown'.

Một số ít phím (esc và các phím mũi tên) có giá trị key không thống nhất trên IE9. Nếu cần hỗ trợ IE9, bạn nên dùng các alias như trên đây.

Các phím modifier hệ thống

Từ phiên bản 2.1.0 trở đi

Bạn có thể sử dụng các modifier sau để chỉ kích hoạt các event listener khi các phím modifier tương ứng dụng được nhấn:

  • .ctrl
  • .alt
  • .shift
  • .meta

Trên các bàn phím của hệ Macintosh, meta là phím Command (⌘). Trên bàn phím Windows, meta là phím Windows (⊞). Trên bàn phím Sun Microsystems, meta được đánh dấu bằng một hình thoi (◆). Trên một số loại bàn phím nhất định như bàn phím của MIT và Lisp, meta có nhãn “META”. Trên bàn phím Symbolics, meta có nhãn “META” hoặc “Meta”.

Ví dụ:

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Cmd + Click -->
<div @click.meta="openNewTab">Mở tab mới</div>

Các phím modifier có cách hoạt động khác với phím thông thường, và khi dùng với sự kiện keyup, phím modifier phải được nhấn khi sự kiện được phát ra. Nói một cách khác, keyup.ctrl sẽ chỉ được kích hoạt khi bạn thả một phím khi vẫn đang ấn phím ctrl. Sự kiện này sẽ không được kích hoạt nếu bạn chỉ thả một mình phím ctrl.

Modifier .exact

2.5.0+

Modifier .exact (chính xác) có thể được sử dụng kết hợp với các modifier khác để chỉ rõ rằng hàm xử lý sự kiện chỉ nên được thực thi khi chính xác tổ hợp phím/chuột đó được bấm.

<!-- onClick vẫn sẽ được gọi nếu người dùng nhấn thêm phím Alt hoặc Shift -->
<button @click.ctrl="onClick">A</button>

<!-- onClick chỉ được gọi nếu chỉ phím Ctrl được nhấn -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- onClick chỉ được kích hoạt khi không có modifier hệ thống nào được nhấn -->
<button @click.exact="onClick">A</button>

Modifier cho phím chuột

Từ phiên bản 2.2.0 trở đi

  • .left
  • .right
  • .middle

Những modifier này giới hạn xử lý cho những sự kiện được kích hoạt bởi một phím chuột nhất định (trái, phải, hoặc giữa).

Tại sao lại lắng nghe sự kiện trong HTML?

Bạn có thể lo ngại rằng toàn bộ việc lắng nghe sự kiện bằng cách đặt event listener trong HTML như thế này là vi phạm quy tắc “separation of concerns.” Cứ yên tâm, vì tất cả các hàm và biểu thức xử lý sự kiện của Vue được ràng buộc chặt chẽ với ViewModel, sẽ không có khó khăn gì trong việc bảo trì. Thật ra, sử dụng v-on còn có những lợi ích sau:

  1. Giúp định vị hàm xử lý trong code JavaScript được dễ dàng hơn bằng cách đọc lướt template HTML.

  2. Vì không phải attach hàm xử lý sự kiện trong JavaScript một cách thủ công, code trong ViewModel trở nên thuần logic và không phụ thuộc vào DOM. Điều này giúp chúng ta dễ viết test.

  3. Khi một ViewModel bị hủy, tất cả hàm xử lý sự kiện đính kèm cũng được tự động gỡ bỏ mà không cần bạn phải dọn dẹp.

» Tiếp: Ràng buộc form input
« Trước: Render danh sách (list)
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!