Khái quát chung các mệnh đề bằng cách sử dụng bộ xử lý ngữ cảnh cho phép chúng ta làm việc hiệu quả hơn. Chúng ta có thể tách phần highlight nút được chọn vào một bộ xử lý riêng, bởi vì nó giống nhau ở cả 3 nút. Cho nên chúng ta có thể làm như sau:
$(document).ready(function() { $('#switcher-default').bind('click', function() { $('body').removeClass('red').removeClass('green'); }); $('#switcher-red').bind('click', function(){ $('body').addClass('red').removeClass('green'); }); $('#switcher-green').bind('click', function() { $('body').addClass('green').removeClass('red'); }); $('#switcher .button').bind('click', function() { $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); });
Đoạn tối ưu hoá mã này sử dụng 3 chức năng của jQuery mà chúng ta đã học. Đầu tiên là vòng lặp ẩn được sử dụng để gắn cùng một bộ xử lý click cho mỗi nút bấm với một lần gọi .bind(). Thứ hai, thứ tự cách xử lý cho phép chúng ta gán hai hàm cho cùng một sự kiện click mà hàm thứ 2 không đè lên hàm thứ nhất. Cuối cùng, chúng ta sử dụng khả năng kết hợp của jQuery để ghép hai đoạn thêm và bỏ class trên cùng một dòng.
#Tiếp tục tối giản mã
Công đoạn tối ưu hoá mã chúng ta vừa làm ở trên là một ví dụ của tái cơ cấu. Tái cơ cấu mã có nghĩa là chúng ta phải chỉnh sửa mã đang có sao cho nó có thể hoạt động hiệu quả hơn và gọn gàng hơn. Để tìm ra thêm những yếu tố khác có thể tái cơ cấu mã, chúng ta hãy xem xét những cách xử lý mà chúng ta vừa gắn cho mỗi nút. Tham số của phương thức .removeClass() là không bắt buộc, khi được bỏ qua, nó loại bỏ tất cả các class của phần tử. Dựa vào điều này, chúng ta có thể rút ngắn mã xuống chút xíu nữa.
$(document).ready(function() { $('#switcher-default').bind('click', function() { $('body').removeClass(); }); $('#switcher-red').bind('click', function(){ $('body').removeClass().addClass('red'); }); $('#switcher-green').bind('click', function() { $('body').removeClass().addClass('green'); }); $('#switcher .button').bind('click', function() { $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); });
Ở đoạn mã trên thứ tự của các tác vụ bị thay đổi một chút để phù hợp với việc loại bỏ class không sử dụng tham số. Chúng ta cần phải gọi phương thức .removeClass() trước, như thế nó sẽ không loại bỏ mất class khi chúng ta gọi .addClass() trên cùng một dòng.
Lưu ý: Trong ví dụ này chúng ta có toàn quyền quyết định với mã HTML, cho nên chúng ta có thể loại bỏ toàn bộ class. Tuy nhiên khi chúng ta viết mã để sử dụng lại (như là viết một Plugin), thì chúng ta nên tôn trọng những class khác và giữ nguyên chúng.
Hiện tại chúng ta vẫn chạy cùng một đoạn mã cho mỗi bộ xử lý nút bấm. Phần này có thể tái cơ cấu rất dễ dàng bởi một bộ xử lý nút chung:
$(document).ready(function() { $('#switcher .button').bind('click', function() { $('body').removeClass(); $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); $('#switcher-red').bind('click', function(){ $('body').removeClass().addClass('red'); }); $('#switcher-green').bind('click', function() { $('body').removeClass().addClass('green'); }); });
Chúng ta đã di chuyển bộ xử lý nút chung lên trên những nút khác. Vậy nên phương thức .removeClass() cần phải xảy ra trước khi phương thức .addClass() được gọi. Việc này có thể làm được bởi vì jQuery luôn kích hoạt bộ xử lý sự kiện theo thứ tự mà chúng được đăng ký.
Cuối cùng chúng ta cũng có thể loại bỏ luôn cả các bộ xử lý cho từng nút bằng cách sử dụng sự kiên ngữ cảnh. Bởi vì từ khoá this cho chúng ta một phần tử DOM chứ không phải là một một đối tượng jQuery, chúng ta có thể sư dụng những tính năng của DOM để xác định ID của mỗi phần tử khi nó được click. Do đó chúng ta có thể gán cùng một bộ xử lý cho tất cả các nút, và những bộ xử lý này tiến hành những tác vụ khác nhau cho mỗi nút bấm.
$(document).ready(function() { $('#switcher .button').bind('click', function() { $('body').removeClass(); if (this.id == 'switcher-red') { $('body').addClass('red'); } else if (this.id == 'switcher-green') { $('body').addClass('green'); } $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); });
Trên đây chúng ta chỉ sử dụng một mệnh đề if … else bình thường để kiểm tra xem nút đang được click có ID là gì rồi đưa ra cách xử lý tương ứng cho từng trường hợp.
#Những sự kiện viết tắt
Gắn một bộ xử lý cho một sự kiện (ví dụ như là một sự kiên click) rất thường xảy ra, cho nên jQuery cung cấp một cách ngắn gọn hơn. Đó chính là những phương pháp viết tắt sự kiện, nó hoạt động giống như khi chúng ta sử dụng .bind() nhưng tiết kiệm được vài chữ.
Ví dụ, đoạn mã của chúng ta có thể sử dụng .click() thay vì .bind() như sau:
$(document).ready(function() { $('#switcher .button').click(function() { $('body').removeClass(); if (this.id == 'switcher-red') { $('body').addClass('red'); } else if (this.id == 'switcher-green') { $('body').addClass('green'); } $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); });
Những phương pháp viết tắt sự kiện như thế này tồn tại với tất cả những sự kiện DOM tiêu chuẩn:
- blur
- change
- click
- dblclick
- error
- focus
- keydown
- keypress
- keyup
- load
- mousedown
- mousemove
- mouseout
- mouseover
- mouseup resize
- scroll
- select
- submit
- unload
Mỗi phương pháp viết tắt sẽ gán một bộ xử lý vào một sự kiện với tên tương ứng
#Sự kiện phức hợp
Mỗi một phương thức xử lý sự kiện của jQuery đều tương ứng trực tiếp với một sự kiện thuần JavaScript. Tuy nhiên, jQuery có một vài bộ xử lý riêng được thêm vào cho dễ sử dụng và tối ưu hoá việc tương thích các trình duyệt. Một trong những phương thức này chính là .ready(), mà chúng ta đã bàn ở trên. Hai phương thức .toggle() và .hover() là hai bộ xử lý sự kiện tuỳ chỉnh nữa của jQuery. Chúng đều được gọi là bộ xử lý sự kiện phức hợp bởi vì chúng tương tác với người dùng và phản ứng lại với họ sử dụng nhiều hơn một hàm.
#Ẩn và hiện những tính năng tiên tiến
Giả sử chúng ta muốn ẩn bộ thay đổi màu sắc khi không cần thiết bằng cách làm cho ba nút biến mất. Chúng ta sẽ cho phép người dùng nhấp chuột vào phần tiêu đề “đổi kiểu dáng” để ẩn nút ấn đi nhưng vẫn giữ nguyên tiêu đề. Nếu người dùng nhấp chuột thêm lần nữa sẽ hiện lại các nút bấm. Chúng ta cần thêm một class nữa để xử lý những nút được ẩn.
.hidden { display: none; }
Chúng ta có thể thêm chức năng vừa nói ở trên vào bằng cách lưu trạng thái hiện tại của nút vào một biến, sau đó kiểm tra giá trị của nó mỗi khi tiêu đề được nhấp để xác định nên hay không nên loại bỏ class=’hidden’ trên các nút bấm. Chúng ta cũng có thể kiểm tra trực tiếp sự hiện diện của class trên một nút, và sử dụng thông tin này để quyết định sẽ phải làm gì. Nhưng thay vào đó, jQuery cho chúng ta một phương thức gọi là .toggle(), sẽ làm tất cả những việc phức tạp trên cho mình.
Phương thức .toggle() có thể lấy hai hoặc nhiều tham số, mỗi một tham số là một hàm. Khi nhấp chuột lần đầu sẽ chạy hàm thứ nhất, nhấp chuột lần thứ hai sẽ kích hoạt hàm thứ hai v.v.. Khi mỗi hàm đã được kích hoạt, vòng lặp lại bắt đầu từ hàm nhứ nhất. Với .toggle(), chúng ta có thể tiến hành ẩn hiện nút thay đổi kiểu dáng khá đơn giản:
$(document).ready(function() { $('#switcher h3').toggle(function() { $('#switcher .button').addClass('hidden'); }, function() { $('#switcher .button').removeClass('hidden'); }); $('#switcher .button').click(function() { $('body').removeClass(); if (this.id == 'switcher-red') { $('body').addClass('red'); } else if (this.id == 'switcher-green') { $('body').addClass('green'); } $('#switcher .button').removeClass('selected'); $(this).addClass('selected'); }); });
Sau khi nhấp chuột một lần nút sẽ bị ẩn đi

Nhấp chuột thêm lần nữa sẽ hiện lại

Một lần nữa chúng ta lại sử dụng vòng lặp ẩn để ẩn các nút đi mà không cần phải sử dụng đến một phần tử bao quanh. Với trường hợp cụ thể này, jQuery cung cấp một cách nữa dùng để ẩn hiện bộ nút của chúng ta. Chúng ta có thể sử dụng phương thức .toggleClass() để tự động kiểm tra sự hiện diện của class trước khi thêm hoặc loại bỏ nó
$(document).ready(function() { $('#switcher h3').click(function() { $('#switcher .button').toggleClass('hidden') });
Trong trường hợp này, .toggleClass() là giải pháp hay hơn, nhưng .toggle() là cách linh hoạt hơn khi tiến hành hai hoặc nhiều tác vụ khác nhau.
#Highlight nút bấm
Để chứng minh cho khả năng của sự kiện click có thể làm việc với những thành phần không nhấp chuột được, chúng ta đã tạo ra một giao diện với nhứng nút mà thực chất chỉ là những thẻ div trở thành một phần sống động của trang, trực chờ người dùng sử dụng nó. Bây giờ chúng ta có thể làm cho nút bấm có thể thay đổi trạng thái khi di chuột qua, cho người dùng biết rằng những nút này sẽ làm một việc gì đó nếu được bấm.
#switcher .hover { cursor: pointer background-color: #afa; }
CSS cung cấp một pseudo-class gọi là :hover, cho phép styesheet chi phối một thành phần khi người dùng di chuột qua nó. Nhưng trong IE6, chức năng này bị giới hạn chỉ với những đường liên kết, cho nên chúng ta không sử dụng nó cho tất cả các trình duyệt được. Thay vào đó, jQuery cho phép chúng ta sử dụng JavaScript để thay đổi kiểu dáng của một phần tử và có thể tiến hành bất cứ tác vụ nào lên nó. Kể cả khi di chuột lên phần tử và di chuột ra khỏi phần tử đó.
Phương thức .hover() lấy hai tham số, giống như ví dụ về .toggle() ở trên. Trong trường hợp này, hàm đầu tiên sẽ được thực hiện khi chuột di qua nó và hàm thứ hai sẽ được kích hoạt khi chuột ra khỏi nó. Chúng ta có thể thay đổi class cho các nút tại thời điểm này để tạo ra hiệu ứng rollover:
$(document).ready(function() { $('#switcher h3').click(function() { $('#switcher .button').toggleClass('hidden') }); $('#switcher .button').hover(function() { $(this).addClass('hover'); }, function() { $(this).removeClass('hover'); });
Chúng ta lại một lần nữa sử dụng vòng lặp ẩn và ngữ cảnh sự kiện để có đoạn mã ngắn hơn và đơn giản hơn. Nếu bây giờ khi bạn di chuột qua các nút bấm, bạn sẽ thấy được hiệu ứng Rollover như hình

Sử dụng .hover() cũng giúp chúng ta tránh được những rắc rối tạo ra bởi lan truyền sự kiện (event propagation) trong JavaScript. Để hiểu được lan truyền sự kiện là gì, chúng ta hãy xem xét JavaScript quyết định phần tử nào sẽ được xử lý kiện.
#Đường đi của một sự kiện
Khi một sự kiện xảy ra trên một trang, toàn bộ cấu trúc bậc thang của các phần tử DOM đều có cơ hội để xử lý sự kiện. Thử tưởng tượng một mô hình như sau:
<div class='mainContent'> <span class='date'><a href='httt://www.izwebz.com'>jQuery tutorial from izwebz</a></span> <p> Khi một sự kiện xảy ra trên một trang, toàn bộ cấu trúc bậc thang của các phần tử DOM đều có cơ hội để xử lý sự kiện. </p>
Chúng ta có thể hình tượng hoá đoạn code trên với hình minh họa sau

Với mỗi một sự kiện, sẽ có nhiều phần tử có thể chịu trách nhiệm xử lý. Ví dụ khi đường link ở ví dụ trên được bấm thì ba thành phần như <div>, <span> và <a> đều có cơ hội để phản ứng lại click đó. Bởi vì bạn thấy cả 3 thành phần trên đều nằm dưới con trỏ chuột của người dùng. Nhưng phần tử <p> lại không nằm trong mối tương tác này.