Tạo biểu mẫu nhiều bước hiệu quả để có trải nghiệm người dùng tốt hơn

theanh

Administrator
Nhân viên
Đối với biểu mẫu nhiều bước, việc lập kế hoạch bao gồm việc sắp xếp các câu hỏi một cách hợp lý theo từng bước, nhóm các câu hỏi tương tự nhau và giảm thiểu số bước cũng như lượng thông tin cần thiết cho mỗi bước. Bất cứ điều gì làm cho từng bước trở nên tập trung và dễ quản lý đều là mục tiêu cần hướng tới.

Trong hướng dẫn này, chúng ta sẽ tạo biểu mẫu nhiều bước cho đơn xin việc. Sau đây là các thông tin chi tiết mà chúng ta sẽ yêu cầu ứng viên cung cấp ở mỗi bước:
  • Thông tin cá nhân
    Thu thập tên, email và số điện thoại của ứng viên.
  • Kinh nghiệm làm việc
    Thu thập công ty gần đây nhất, chức danh công việc và số năm kinh nghiệm của ứng viên.
  • Kỹ năng & Trình độ
    Ứng viên liệt kê các kỹ năng của mình và chọn bằng cấp cao nhất.
  • Xem xét & Nộp
    Bước này sẽ không thu thập bất kỳ thông tin nào. Thay vào đó, nó cung cấp cho người nộp đơn cơ hội quay lại và xem lại thông tin đã nhập ở các bước trước của biểu mẫu trước khi gửi.
Bạn có thể nghĩ về việc cấu trúc các câu hỏi này như một cách kỹ thuật số để tìm hiểu ai đó. Bạn không thể gặp ai đó lần đầu tiên và hỏi họ về kinh nghiệm làm việc của họ mà không hỏi tên họ trước.

Dựa trên các bước chúng tôi đã nêu ở trên, đây là nội dung của HTML với biểu mẫu của chúng tôi sẽ trông như thế nào. Đầu tiên, phần tử chính:
Mã:
Bước 1 là để điền thông tin cá nhân, như tên, địa chỉ email và số điện thoại của người nộp đơn:
Mã:
   Bước 1: Thông tin cá nhân Họ và tên  Địa chỉ email  Số điện thoại
Sau khi người nộp đơn hoàn tất bước đầu tiên, chúng tôi sẽ hướng dẫn họ đến Bước 2, tập trung vào kinh nghiệm làm việc của họ để chúng tôi có thể thu thập thông tin như công ty gần đây nhất, chức danh công việc và số năm kinh nghiệm. Chúng tôi sẽ thêm một mới với các thông tin đầu vào đó:
Mã:
    Bước 2: Kinh nghiệm làm việc Công ty gần đây nhất  Chức danh công việc  Số năm kinh nghiệm
Bước 3 là về việc ứng viên liệt kê các kỹ năng và bằng cấp của họ cho công việc mà họ đang ứng tuyển:
Mã:
     Bước 3: Kỹ năng và bằng cấp Kỹ năng  Bằng cấp đạt được (Cao nhất)  Chọn Bằng cấp Bằng Tốt nghiệp Trung học Phổ thông Bằng Cử nhân Bằng Thạc sĩ Tiến sĩ     Bước 4: Xem xét & Nộp 
Xem lại thông tin của bạn trước khi nộp đơn.
 Nộp đơn
Và cuối cùng, chúng tôi sẽ cho phép người nộp đơn xem lại thông tin của họ trước khi nộp:
Mã:
      Bước 4: Xem lại & Nộp 
Xem lại thông tin của bạn trước khi nộp đơn.
 Nộp đơn
Lưu ý: Chúng tôi đã thêm thuộc tính hidden vào mọi phần tử fieldset trừ phần tử đầu tiên. Điều này đảm bảo rằng người dùng chỉ nhìn thấy bước đầu tiên. Sau khi hoàn tất bước đầu tiên, họ có thể tiếp tục điền kinh nghiệm làm việc của mình vào bước thứ hai bằng cách nhấp vào nút điều hướng. Chúng tôi sẽ thêm nút này sau.

Thêm Kiểu​

Để tập trung, chúng tôi sẽ không nhấn mạnh vào các kiểu trong hướng dẫn này. Những gì chúng ta sẽ làm để giữ mọi thứ đơn giản là tận dụng khung kiểu Simple.css để có được biểu mẫu ở dạng tốt cho phần còn lại của hướng dẫn.

Nếu bạn đang theo dõi, chúng ta có thể đưa các kiểu của Simple vào tài liệu :
Mã:
Và từ đó, hãy tiếp tục và tạo tệp style.css với các kiểu sau mà tôi đã gấp lại.
Mã:
 View CSS body { min-height: 100vh; display: flex; align-items: center; justify-content: center; } main { padding: 0 30px; } h1 { font-size: 1.8rem; text-align: center; } .stepper { display: flex; justify-content: flex-end; padding-right: 10px; } form { box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.2); padding: 12px; } input, textarea, select { outline: none; } input:valid, textarea:valid, select:valid, input:focus:valid, textarea:focus:valid, select:focus:valid { border-color: green; } input:focus:invalid, textarea:focus:invalid, select:focus:invalid { border: 1px solid red; }

Điều hướng và xác thực biểu mẫu​

Một cách dễ dàng để phá hỏng trải nghiệm người dùng đối với biểu mẫu nhiều bước là đợi cho đến khi người dùng đến bước cuối cùng trong biểu mẫu trước khi cho họ biết bất kỳ lỗi nào họ đã mắc phải trong quá trình thực hiện. Mỗi bước của biểu mẫu phải được xác thực lỗi trước khi chuyển sang bước tiếp theo và các thông báo lỗi mô tả phải được hiển thị để người dùng hiểu được lỗi sai và cách khắc phục.

Bây giờ, phần duy nhất của biểu mẫu của chúng ta có thể nhìn thấy là bước đầu tiên. Để hoàn thành biểu mẫu, người dùng cần có thể điều hướng đến các bước khác. Chúng ta sẽ sử dụng một số nút để thực hiện việc này. Bước đầu tiên sẽ có nút Tiếp theo. Bước thứ hai và thứ ba sẽ có cả nút Trước và nút Tiếp theo, và bước thứ tư sẽ có nút Trước và nút Gửi.
Mã:
    Next     Previous Next     Previous Next     Previous Nộp đơn
Lưu ý: Chúng tôi đã thêm thuộc tính onclick vào các nút Trước và Tiếp theo để liên kết chúng với các hàm JavaScript tương ứng: previousStep()nextStep().

Nút "Tiếp theo"​

Hàm nextStep() được liên kết với nút Tiếp theo. Bất cứ khi nào người dùng nhấp vào nút Tiếp theo, hàm nextStep() trước tiên sẽ kiểm tra để đảm bảo rằng tất cả các trường cho bất kỳ bước nào mà người dùng đang thực hiện đã được điền chính xác trước khi chuyển sang bước tiếp theo. Nếu các trường không được điền chính xác, nó sẽ hiển thị một số thông báo lỗi, cho người dùng biết rằng họ đã làm sai điều gì đó và thông báo cho họ biết phải làm gì để khắc phục lỗi.

Trước khi đi vào triển khai hàm nextStep, có một số biến nhất định mà chúng ta cần xác định vì chúng sẽ cần thiết trong hàm. Đầu tiên, chúng ta cần các trường nhập từ DOM để có thể chạy kiểm tra chúng nhằm đảm bảo chúng hợp lệ.
Mã:
// Các trường ở Bước 1const name = document.getElementById("name");const email = document.getElementById("email");const phone = document.getElementById("phone");// Các trường ở Bước 2const company = document.getElementById("company");const jobTitle = document.getElementById("jobTitle");const yearsExperience = document.getElementById("yearsExperience");// Các trường Bước 3const skills = document.getElementById("skills");const highestDegree = document.getElementById("highestDegree");
Sau đó, chúng ta sẽ cần một mảng để lưu trữ các thông báo lỗi của mình.
Mã:
let errorMsgs = [];
Ngoài ra, chúng ta sẽ cần một phần tử trong DOM nơi chúng ta có thể chèn các thông báo lỗi đó sau khi chúng được tạo. Phần tử này phải được đặt trong HTML ngay bên dưới thẻ đóng fieldset cuối cùng:
Mã:
Thêm div ở trên vào mã JavaScript bằng cách sử dụng dòng sau:
Mã:
const errorMessagesDiv = document.getElementById("errorMessages");
Và cuối cùng, chúng ta cần một biến để theo dõi bước hiện tại.

let currentStep = 1;

Bây giờ chúng ta đã có tất cả các biến tại chỗ, đây là phần triển khai hàm nextstep():
Mã:
function nextStep() { errorMsgs = []; errorMessagesDiv.innerText = ""; switch (currentStep) { case 1: addValidationErrors(name, email, phone); validateStep(errorMsgs); break; case 2: addValidationErrors(company, jobTitle, yearsExperience); validateStep(errorMsgs); break; case 3: addValidationErrors(skills, highestDegree); validateStep(errorMsgs); break; }}
Ngay khi nhấn nút Next, mã của chúng tôi sẽ kiểm tra xem người dùng hiện đang ở bước nào và dựa trên thông tin này, mã sẽ xác thực dữ liệu cho bước cụ thể đó bằng cách gọi hàm addValidationErrors(). Nếu có lỗi, chúng tôi sẽ hiển thị lỗi. Sau đó, biểu mẫu sẽ gọi hàm validateStep() để xác minh rằng không có lỗi nào trước khi chuyển sang bước tiếp theo. Nếu có lỗi, người dùng sẽ không thể chuyển sang bước tiếp theo.

Bất cứ khi nào hàm nextStep() chạy, các thông báo lỗi sẽ được xóa trước để tránh thêm lỗi từ một bước khác vào lỗi hiện có hoặc thêm lại các thông báo lỗi hiện có khi hàm addValidationErrors chạy. Hàm addValidationErrors được gọi cho từng bước bằng cách sử dụng các trường cho bước đó làm đối số.

Sau đây là cách hàm addValidationErrors được triển khai:
Mã:
function addValidationErrors(fieldOne, fieldTwo, fieldThree = undefined) { if (!fieldOne.checkValidity()) { const label = document.querySelector(`label[for="${fieldOne.id}"]`); errorMsgs.push(`Vui lòng nhập ${label.textContent} hợp lệ`); } if (!fieldTwo.checkValidity()) { const label = document.querySelector(`label[for="${fieldTwo.id}"]`); errorMsgs.push(`Vui lòng nhập ${label.textContent} hợp lệ`); } if (fieldThree && !fieldThree.checkValidity()) { const label = document.querySelector(`label[for="${fieldThree.id}"]`); errorMsgs.push(`Vui lòng nhập ${label.textContent} hợp lệ`); } if (errorMsgs.length > 0) { errorMessagesDiv.innerText = errorMsgs.join("\n"); }}
Đây là cách hàm validateStep() được định nghĩa:
Mã:
function validateStep(errorMsgs) { if (errorMsgs.length === 0) { showStep(currentStep + 1); }}
Hàm validateStep() kiểm tra lỗi. Nếu không có lỗi nào, nó sẽ tiến hành bước tiếp theo với sự trợ giúp của hàm showStep().
Mã:
function showStep(step) { steps.forEach((el, index) => { el.hidden = index + 1 !== step; }); currentStep = step;}
Hàm showStep() yêu cầu bốn tập trường trong DOM. Thêm dòng sau vào đầu mã JavaScript để làm cho các fieldset khả dụng:
Mã:
const steps = document.querySelectorAll(".step");
Hàm showStep() thực hiện duyệt qua tất cả các fieldset trong biểu mẫu của chúng ta và ẩn bất kỳ fieldset nào không bằng với fieldset mà chúng ta đang điều hướng đến. Sau đó, nó cập nhật biến currentStep để bằng với bước mà chúng ta đang điều hướng đến.

Nút "Trước"​

Hàm previousStep() được liên kết với nút Trước. Bất cứ khi nào nút trước đó được nhấp, tương tự như hàm nextStep, các thông báo lỗi cũng được xóa khỏi trang và việc điều hướng cũng được xử lý bởi hàm showStep.
Mã:
function previousStep() { errorMessagesDiv.innerText = ""; showStep(currentStep - 1);}
Bất cứ khi nào hàm showStep() được gọi với “currentStep - 1” làm đối số (như trong trường hợp này), chúng ta quay lại bước trước đó, trong khi chuyển sang bước tiếp theo xảy ra bằng cách gọi hàm showStep() với “currentStep + 1” làm đối số (như trong trường hợp hàm validateStep()).

Cải thiện trải nghiệm người dùng bằng tín hiệu trực quan​

Một cách khác để cải thiện trải nghiệm người dùng cho biểu mẫu nhiều bước là tích hợp các tín hiệu trực quan, những thứ sẽ cung cấp cho người dùng phản hồi về quy trình họ đang thực hiện. Những thứ này có thể bao gồm một chỉ báo tiến trình hoặc một bước để giúp người dùng biết chính xác họ đang ở bước nào.

Tích hợp một bước​

Để tích hợp một bước vào biểu mẫu của chúng ta (giống như cái này từ Material Design), điều đầu tiên chúng ta cần làm là thêm nó vào HTML ngay bên dưới thẻ mở .
Mã:
  1/4
Tiếp theo, chúng ta cần truy vấn phần của stepper sẽ biểu diễn bước hiện tại. Đây là thẻ span có tên lớp là currentStep.
Mã:
const currentStepDiv = document.querySelector(".currentStep");
Bây giờ, chúng ta cần cập nhật giá trị stepper bất cứ khi nào các nút trước hoặc nút tiếp theo được nhấp vào. Để thực hiện việc này, chúng ta cần cập nhật hàm showStep() bằng cách thêm dòng sau vào hàm:
Mã:
currentStepDiv.innerText = currentStep;
Dòng này được thêm vào hàm showStep() vì hàm showStep() chịu trách nhiệm điều hướng giữa các bước và cập nhật biến currentStep. Vì vậy, bất cứ khi nào biến currentStep được cập nhật, currentStepDiv cũng phải được cập nhật để phản ánh thay đổi đó.

Lưu trữ và truy xuất dữ liệu người dùng​

Một cách chính để cải thiện trải nghiệm người dùng của biểu mẫu là lưu trữ dữ liệu người dùng trong trình duyệt. Biểu mẫu nhiều bước thường dài và yêu cầu người dùng nhập nhiều thông tin về bản thân. Hãy tưởng tượng một người dùng điền 95% biểu mẫu, sau đó vô tình nhấn nút F5 trên bàn phím và mất toàn bộ tiến trình. Đó sẽ là một trải nghiệm thực sự tệ đối với người dùng.

Sử dụng localStorage, chúng ta có thể lưu trữ thông tin người dùng ngay khi nhập vào và truy xuất thông tin đó ngay khi nội dung DOM được tải, do đó người dùng luôn có thể tiếp tục điền vào biểu mẫu của họ từ bất kỳ nơi nào họ dừng lại. Để thêm tính năng này vào biểu mẫu của mình, chúng ta có thể bắt đầu bằng cách lưu thông tin của người dùng ngay khi nhập vào. Có thể thực hiện việc này bằng cách sử dụng sự kiện input.

Trước khi thêm trình lắng nghe sự kiện input, hãy lấy phần tử biểu mẫu từ DOM:
Mã:
const form = document.getElementById("jobApplicationForm");
Bây giờ chúng ta có thể thêm trình lắng nghe sự kiện input:
Mã:
// Lưu dữ liệu trên mỗi sự kiện đầu vàoform.addEventListener("input", () => { const formData = { name: document.getElementById("name").value, email: document.getElementById("email").value, phone: document.getElementById("phone").value, company: document.getElementById("company").value, jobTitle: document.getElementById("jobTitle").value, yearsExperience: document.getElementById("yearsExperience").value, skills: document.getElementById("skills").value, highestDegree: document.getElementById("highestDegree").value, }; localStorage.setItem("formData", JSON.stringify(formData));});
Tiếp theo, chúng ta cần thêm một số mã để giúp chúng ta truy xuất dữ liệu người dùng sau khi nội dung DOM được tải.
Mã:
window.addEventListener("DOMContentLoaded", () => { const savedData = JSON.parse(localStorage.getItem("formData")); if (savedData) { document.getElementById("name").value = savedData.name || ""; document.getElementById("email").value = savedData.email || ""; document.getElementById("điện thoại").giá trị = savedData.phone || ""; document.getElementById("công ty").giá trị = savedData.company || ""; document.getElementById("tiêu đề công việc").giá trị = savedData.jobTitle || ""; document.getElementById("nămKinh nghiệm").giá trị = savedData.yearKinh nghiệm || ""; document.getElementById("kỹ năng").giá trị = savedData.kỹ năng || ""; document.getElementById("bậc cao nhất").giá trị = savedData.bậc cao nhất || ""; }});
Cuối cùng, một cách thực hành tốt là xóa dữ liệu khỏi localStorage ngay khi không còn cần thiết nữa:
Mã:
// Xóa dữ liệu khi gửi biểu mẫuform.addEventListener('submit', () => { // Xóa localStorage sau khi biểu mẫu được gửi localStorage.removeItem('formData');});

Thêm giá trị bước hiện tại vào localStorage

Nếu người dùng vô tình đóng trình duyệt, họ sẽ có thể quay lại nơi họ đã dừng lại. Điều này có nghĩa là giá trị bước hiện tại cũng phải được lưu trong localStorage.

Để lưu giá trị này, hãy thêm dòng sau vào hàm showStep():
Mã:
localStorage.setItem("storedStep", currentStep);
Bây giờ chúng ta có thể truy xuất giá trị bước hiện tại và đưa người dùng trở lại bất cứ nơi nào họ dừng lại bất cứ khi nào nội dung DOM tải. Thêm mã sau vào trình xử lý DOMContentLoaded để thực hiện việc này:
Mã:
const storedStep = localStorage.getItem("storedStep");if (storedStep) { const storedStepInt = parseInt(storedStep); steps.forEach((el, index) => { el.hidden = index + 1 !== storedStepInt; }); currentStep = storedStepInt; currentStepDiv.innerText = currentStep; }
Ngoài ra, đừng quên xóa giá trị bước hiện tại khỏi localStorage khi biểu mẫu được gửi đi.
Mã:
localStorage.removeItem("storedStep");
Dòng trên phải được thêm vào trình xử lý gửi đi.

Kết thúc​

Việc tạo biểu mẫu nhiều bước có thể giúp cải thiện trải nghiệm của người dùng đối với mục nhập dữ liệu phức tạp. Bằng cách lập kế hoạch cẩn thận các bước, triển khai xác thực biểu mẫu ở mỗi bước và lưu trữ tạm thời dữ liệu người dùng trong trình duyệt, bạn giúp người dùng dễ dàng hoàn thành các biểu mẫu dài hơn.

Để triển khai đầy đủ biểu mẫu nhiều bước này, bạn có thể truy cập mã đầy đủ trên GitHub.
 
Back
Bên trên