Nhiều sự kiện tự động dẫn đến các hành động nhất định do trình duyệt thực hiện. Đó là chủ đề hôm nay mà cafedev chia sẻ cho ace, các hành động mặc định của trình duyệt.

Bạn đang xem: Form submit không cần load lại trình duyệt

Ví dụ:

Một cú nhấp chuột vào một liên kết – bắt đầu điều hướng đến URL của nó.Một cú nhấp chuột vào nút gửi biểu mẫu – bắt đầu gửi biểu mẫu đến máy chủ.Nhấn nút chuột trên văn bản và di chuyển văn bản đó – chọn văn bản.

Nếu chúng ta xử lý một sự kiện trong Java
Script, chúng ta có thể không muốn hành động trình duyệt tương ứng xảy ra và thay vào đó, chúng ta muốn triển khai một hành vi khác.


Nội dung chính


1. Ngăn chặn các hành động của trình duyệt2. Tùy chọn trình xử lý “thụ động”

1. Ngăn chặn các hành động của trình duyệt

Có hai cách để cho trình duyệt biết rằng chúng ta không muốn trình duyệt hoạt động:


Cách chính là sử dụng đối tượng event. Có một phương thức event.prevent
Default().Nếu trình xử lý được chỉ định bằng cách sử dụng on(không phải bởi add
Event
Listener), thì việc trả về false cũng hoạt động tương tự.

Trong HTML này, nhấp chuột vào liên kết không dẫn đến điều hướng, trình duyệt không thực hiện bất kỳ điều gì:

Click hereorhere
Trong ví dụ tiếp theo, chúng ta sẽ sử dụng kỹ thuật này để tạo một menu hỗ trợ Java
Script.

Trở về false từ một trình xử lý là một ngoại lệ

Giá trị được trả về bởi một trình xử lý sự kiện thường bị bỏ qua.

Ngoại lệ duy nhất là return false từ một trình xử lý được chỉ định sử dụng on.


Trong tất cả các trường hợp khác, return giá trị bị bỏ qua. Đặc biệt, không có ý nghĩa trong việc quay trở lại true.

1.1. Ví dụ: menu

Hãy xem xét một menu trang web, như sau:

Đây là cách nó trông như thế nào với một số CSS:

Các mục menu được triển khai dưới dạng liên kết HTML , không phải nút . Có một số lý do để làm như vậy, ví dụ:

Nhiều người thích sử dụng “nhấp chuột phải” – “mở trong cửa sổ mới”. Nếu chúng ta sử dụng hoặc , điều đó không hoạt động.Công cụ tìm kiếm theo liên kết trong khi lập chỉ mục.

Vì vậy, chúng ta sử dụng trong đánh dấu. Nhưng thông thường chúng ta định xử lý các nhấp chuột trong Java
Script. Vì vậy, chúng ta nên ngăn chặn hành động mặc định của trình duyệt.

Như đây:

menu.onclick = function(event) { if (event.target.node
Name != "A") return; let href = event.target.get
Attribute("href"); alert( href ); // ...can be loading from the server, UI generation etc return false; // prevent browser action (don"t go to the URL)};Nếu chúng ta bỏ qua return false, thì sau khi mã của chúng ta thực thi, trình duyệt sẽ thực hiện “hành động mặc định” – điều hướng đến URL trong href. Và chúng ta không cần điều đó ở đây, vì chúng ta đang tự xử lý nhấp chuột.

Nhân tiện, việc sử dụng ủy nhiệm sự kiện ở đây làm cho menu của chúng ta rất linh hoạt. Chúng ta có thể thêm các danh sách lồng nhau và tạo kiểu cho chúng bằng cách sử dụng CSS để “trượt xuống”.

Các sự kiện tiếp theo

Các sự kiện nhất định nối tiếp nhau. Nếu chúng ta ngăn chặn sự kiện đầu tiên, sẽ không có sự kiện thứ hai.


Ví dụ, mousedown trên một trường dẫn đến việc tập trung vào đó và sự kiện focus. Nếu chúng ta ngăn cản sự kiện mousedown, sẽ không có trọng tâm.

Hãy thử nhấp vào phần đầu tiên bên dưới – sự kiện focus sẽ xảy ra. Nhưng nếu bạn nhấp vào cái thứ hai, sẽ không có tiêu điểm.

Đó là vì hành động của trình duyệt bị hủy vào mousedown. Vẫn có thể lấy nét nếu chúng ta sử dụng một cách khác để nhập đầu vào. Ví dụ, phím Tab để chuyển từ đầu vào thứ nhất thành thứ hai. Nhưng không phải với cú nhấp chuột nữa.

2. Tùy chọn trình xử lý “thụ động”

Tùy chọn tùy passive: true chọn add
Event
Listener báo hiệu trình duyệt rằng trình xử lý sẽ không gọi prevent
Default().

Tại sao điều đó có thể cần thiết?

Có một số sự kiện như touchmove trên thiết bị di động (khi người dùng di chuyển ngón tay của họ trên màn hình), gây ra việc cuộn theo mặc định, nhưng việc cuộn đó có thể bị ngăn chặn bằng cách sử dụng prevent
Default() trong trình xử lý.

Vì vậy, khi trình duyệt phát hiện sự kiện như vậy, trước tiên nó phải xử lý tất cả các trình xử lý và sau đó nếu prevent
Default không được gọi ở bất kỳ đâu, nó có thể tiến hành cuộn. Điều đó có thể gây ra sự chậm trễ không cần thiết và “giật mình” trong giao diện người dùng.

Các tùy chọn passive: true cho trình duyệt biết rằng trình xử lý sẽ không hủy thao tác cuộn. Sau đó, trình duyệt sẽ cuộn ngay lập tức cung cấp trải nghiệm lưu loát tối đa và sự kiện được xử lý theo cách này.

Đối với một số trình duyệt (Firefox, Chrome), passive là true theo mặc định cho sự kiện touchstart và touchmove.

2.1. event.default
Prevented

Thuộc tính event.default
Prevented là true nếu hành động mặc định bị ngăn chặn, và false nếu không.


Có một trường hợp sử dụng thú vị cho nó.

Bạn còn nhớ trong chương Sủi Event.stop
Propagation() bọt và bắt chúng ta đã nói đến và tại sao ngừng sủi bọt lại là điều không tốt?

Đôi khi chúng ta có thể sử dụng event.default
Prevented thay thế để báo hiệu cho các trình xử lý sự kiện khác rằng sự kiện đã được xử lý.

Hãy xem một ví dụ thực tế.

Theo mặc định, trình duyệt khi sự kiện context menu (nhấp chuột phải) hiển thị menu ngữ cảnh với các tùy chọn tiêu chuẩn. Chúng ta có thể ngăn chặn nó và hiển thị của riêng chúng tôi, như thế này:

Right-click shows browser context menu Right-click shows our context menu
Bây giờ, ngoài menu ngữ cảnh đó, chúng ta muốn triển khai menu ngữ cảnh trên toàn tài liệu.

Khi nhấp chuột phải, menu ngữ cảnh gần nhất sẽ hiển thị.

Right-click here for the document context menu

Right-click here for the button context menu

Vấn đề là khi chúng ta nhấp vào elem, chúng ta nhận được hai menu: menu cấp độ nút và (sự kiện bong bóng) menu cấp độ tài liệu.

Làm thế nào để sửa chữa nó? Một trong những giải pháp là suy nghĩ như: “Khi chúng ta xử lý nhấp chuột phải vào trình xử lý nút, hãy ngừng sủi bọt” và sử dụng event.stop
Propagation():

Right-click for the document menu

Right-click for the button menu (fixed with event.stop
Propagation)

Bây giờ menu cấp nút hoạt động như dự định. Nhưng giá cao. Chúng ta vĩnh viễn từ chối quyền truy cập vào thông tin về nhấp chuột phải cho bất kỳ code bên ngoài nào, bao gồm cả bộ đếm thu thập số liệu thống kê, v.v. Điều đó khá thiếu khôn ngoan.


Một giải pháp thay thế sẽ là kiểm tra trong trình xử lý document nếu hành động mặc định bị ngăn chặn? Nếu đúng như vậy, thì sự kiện đã được xử lý và chúng ta không cần phải phản ứng với nó.

Right-click for the document menu (added a check for event.default
Prevented)

Right-click for the button menu

Bây giờ mọi thứ cũng hoạt động chính xác. Nếu chúng ta có các phần tử lồng nhau và mỗi phần tử có một menu ngữ cảnh riêng, thì điều đó cũng sẽ hoạt động. Chỉ cần đảm bảo kiểm tra event.default
Prevented từng trình xử lý contextmenu.

event.stop
Propagation () và event.prevent
Default ()

Như chúng ta có thể thấy rõ, event.stop
Propagation()và event.prevent
Default()(còn được gọi là return false) là hai thứ khác nhau. Chúng không liên quan đến nhau.

Kiến trúc menu ngữ cảnh lồng nhau

Ngoài ra còn có những cách thay thế để triển khai các menu ngữ cảnh lồng nhau. Một trong số đó là có một đối tượng toàn cục duy nhất với trình xử lý cho document.oncontextmenu và cả các phương thức cho phép chúng ta lưu trữ các trình xử lý khác trong đó.

Đối tượng sẽ bắt bất kỳ lần nhấp chuột phải nào, xem qua các trình xử lý được lưu trữ và chạy trình xử lý thích hợp.

Nhưng sau đó, mỗi đoạn code muốn có menu ngữ cảnh phải biết về đối tượng đó và sử dụng trợ giúp của nó thay vì trình xử lý contextmenu riêng .

3. Tóm lược

Có nhiều hành động trình duyệt mặc định:

mousedown – bắt đầu lựa chọn (di chuyển chuột để chọn).click – kiểm tra / bỏ chọn input.submit- việc nhấp vào hoặc nhấn Enter vào bên trong trường biểu mẫu khiến sự kiện này xảy ra và trình duyệt gửi biểu mẫu sau đó.keydown – nhấn phím có thể dẫn đến việc thêm một ký tự vào một trường hoặc các hành động khác.contextmenu – sự kiện xảy ra khi nhấp chuột phải, hành động là hiển thị menu ngữ cảnh của trình duyệt.…có nhiều…

Tất cả các hành động mặc định có thể bị ngăn chặn nếu chúng ta muốn xử lý sự kiện độc quyền bằng Java
Script.


Để ngăn hành động mặc định – sử dụng event.prevent
Default() hoặc return false. Phương thức thứ hai chỉ hoạt động cho các trình xử lý được gán với on.

Các tùy chọn passive: true cho trình duyệt add
Event
Listener rằng hành động sẽ không được ngăn chặn. Điều này hữu ích cho một số sự kiện trên thiết bị di động, chẳng hạn như touchstart và touchmove, để nói với trình duyệt rằng nó không nên đợi tất cả các trình xử lý hoàn tất trước khi cuộn.

Nếu hành động mặc định bị ngăn chặn, giá trị của event.default
Prevented sẽ trở thành true, nếu không thì giá trị đó là false.

Giữ ngữ nghĩa, không lạm dụng

Về mặt kỹ thuật, bằng cách ngăn các hành động mặc định và thêm Java
Script, chúng ta có thể tùy chỉnh hành vi của bất kỳ phần tử nào. Ví dụ: chúng ta có thể làm cho một liên kết hoạt động giống như một nút và một nút hoạt động như một liên kết (chuyển hướng đến một URL khác hoặc tương tự như vậy).

Nhưng nói chung chúng ta nên giữ ý nghĩa ngữ nghĩa của các phần tử HTML. Ví dụ, nên thực hiện điều hướng, không phải một nút.

Bên cạnh việc “chỉ là một điều tốt”, điều đó còn làm cho HTML của bạn tốt hơn về khả năng truy cập.

Ngoài ra, nếu chúng ta xem xét ví dụ với , thì xin lưu ý: trình duyệt cho phép chúng ta mở các liên kết như vậy trong một cửa sổ mới (bằng cách nhấp chuột phải vào chúng và các phương tiện khác). Và những người như thế. Nhưng nếu chúng ta làm cho một nút hoạt động như một liên kết bằng Java
Script và thậm chí trông giống như một liên kết sử dụng CSS, thì các tính năng cụ thể của trình duyệt vẫn sẽ không hoạt động với nó.

Bài viết này hướng dẫn cách submit form mà không tải lại trang tạo ra trải nghiệm liền mạch, đặc biệt là với các Web App.


*
Hướng dẫn cách submit HTML form không tải lại trang

Tại sao nên thiết kế form submit không cần tải lại trang

Xu hướng thiết kế website hiện nay là tạo ra trải nghiệm liền mạch, không có độ trễ, đặc biệt là với các Web App mong muốn đem lại trải nghiệm như Native App trên Smart phone. Phong cách website kiểu này gọi là Single Page Application.

Với thiết kế này, Server chỉ thực hiện nhiệm vụ xử lý và trao đổi dữ liệu với Client qua REST API. Việc render giao diện sẽ nằm ở Client với HTML5, CSS3 và các framework Java
Script như Angular
JS hay Vue.JS v.v… Như vậy là cũng giảm tải chút chút cho Server.


*
Single Page Application – Mọi tương tác giữa client và server chủ yếu là trao đổi dữ liệu

Giải pháp trao đổi dữ liệu không tải lại trang ở đây là sử dụng AJAX để thực hiện request và nhận lại dữ liệu dưới dạng một data format nào đó dễ dàng xử lý bằng Java
Script, ví du JSON hoặc XML.

Cách dùng j
Query.ajax để submit form không tải lại trang

JQuery cung cấp 3 hàm cho phép chúng ta thực hiện AJAX request đó là $.ajax, $.get và $.post, trong đó $.get và $.post chính là wrapper của $.ajax dành riêng cho GET và POST method vì vậy tôi sẽ không dùng chúng.

Dưới đây là một ví dụ sử dụng $.ajax() để submit form mà không cần reload. Giả sử ta có một form như sau:

Đoạn mã Java
Script sau sử dụng $.ajax của thư viện j
Query để submit form này.

$(document).ready(function() { $("form").submit(function(event) { $.ajax({ method: $(this).attr("method"), url: $(this).attr("action"), data: $(this).serialize(), /* ... other AJAX settings ... */ }).done(function(response) { // Process the response here }); event.prevent
Default(); // Lưu ý, để ngăn tải lại trang, ta phải gọi event.prevent
Default() hoặc đơn giản là return false trong callback của $.submit().

Ở đây ta sử dụng hàm $.serialize để tách dữ liệu từ form thành Query String, phù hợp với Content
Type mặc định là application/x-www-form-urlencoded; charset=UTF-8.

Nếu form của chúng ta gửi có cấu trúc dữ liệu phức tạp thì hãy tham khảo giải pháp tạo HTML Form chứa object và array.

Upload file với j
Query.ajax và Form
Data

Để upload được file với AJAX, ta cần sự hỗ trợ của đối tượng Form
Data. Về cơ bản đối tượng Form
Data cho phép ta gửi dữ liệu kiểu key/value thông qua giao diện XMLHttp
Request giống như khi submit().

Ví dụ với form như sau có các trường thông tin thông thường và kèm với cả một trường lựa chọn file. Lưu ý định dạng encoding type cho form có file upload là multipart/form-data.

Phần xử lý form có chút thay đổi đó là thay vì dùng $.serialize() thì ta sử dụng Form
Data như sau:

Data(this), cache: false, // do not cache this request content
Type: false, // prevent missing boundary string process
Data: false, // do not transform to query string timeout: 60000, xhr: function () { var xhr = $.ajax
Settings.xhr(); if (xhr.upload) { xhr.upload.add
Event
Listener("progress", progress
Handler, false); } return xhr; }, }).done(function(response) { // Process the response here }); event.prevent
Default(); }); // Handle file upload progress function progress
Handler(event) { var percent = 0; var position = event.loaded || event.position; var total = event.total; if (event.length
Computable) { percent = Math.ceil(position / total * 100); } // display the progress console.log("Uploading ", percent + "%"); }});Lưu ý thêm là ta cần bổ sung cấu hình sau cho $.ajax() nếu không request sẽ bị lỗi:

cache: false – Ngăn trình duyệt không cache request này.content
Type: false – Không cho j
Query gửi Content Type, nếu không sẽ làm mất chuỗi Boundary trong request.process
Data: false – Không cho j
Query tự động xử lý data thành query string.

Xem thêm: Bến Xe Phương Trang Đà Nẵng Nha Trang Đà Nẵng ❤️ Địa Chỉ, Số Điện Thoại, Giá Vé

P/S: Hàm xử lý trên có bonus thêm một phần xử lý upload progress là progress
Handler. Hãy thay đổi nội dung theo ý của bạn.