Sử dụng Header với menu nhiều lớp cần xử lý tinh tế trong UX và là câu hỏi được nhiều lập trình viên quan tâm. Trong bài viết này, tôi xin hướng dẫn các bạn cách thức thực hiện gọn gàng và dễ nhìn nhất.
Header Accordion là gì?
“Accordion” là tính năng cho phép đóng mở nội dung ẩn của một khu vực. Khi nhấp vào một item trong danh sách, nó sẽ mở ra phần nội dung bên dưới.
Accordion có ứng dụng rộng rãi trong nhiều phần của website, nhưng phổ biến nhất là sử dụng làm module FAQ (Câu hỏi thường gặp).
Trong bài viết này, ta sẽ thử ứng dụng module Accordion này vào làm một việc khác: sử dụng trong Header ở trạng thái trên mobile.
Bài toán Header chứa Accordion
Ta có những dữ liệu cụ thể như sau:
Khách hàng sử dụng website WordPress, trong đó chức năng menu là sử dụng hoàn toàn tính năng built-in của WordPress.
Trên khung màn hình máy tính, khách hàng muốn hover chuột là hiện ra sub-menu phụ.
Trên màn hình mobile, thay vì hover, người dùng phải nhấp chuột vào item cha để hiện ra các sub-menu con.
Vì đây là một bài toán cơ bản, nhưng do tính chất cần tiếp cận với số đông lập trình viên có thói quen sử dụng jQuery, ta sẽ mô phỏng lại bằng cách giữ jQuery của WordPress và cập nhật cho nó hoạt động.
Tạo markup PHP kết hợp BEM Class
Cấu trúc markup của tôi thực ra rất đơn giản, kết hợp đặt tên class theo BEM:
Tiếp đến, tôi cần tạo một lớp menu trong backend chứa sub-menu như trong hình:
Lưu ý, để thêm vào đúng menu, bạn còn cần bước đăng ký menu trong functions.php như register_nav_menus của theme Twenty Seventeen nhé.
Markup khi tạo ra có thể sẽ như thế này:
<header class="header" data-module-init="header"> <div class="header__wrapper"> <nav class="header__nav"> <ul class="header__menu"> <li class="menu-item"><a href="a/demo/1">First Item</a></li> <li class="menu-item menu-item-has-children"> <a href="a/demo/2">Second Item</a> <ul class="sub-menu"> <li class="menu-item"> <a href="a/demo/3">First Sub Item</a> </li> </ul> </li> </ul> </nav> </div> </header>
Khởi tạo module Javascript
Giờ, sau khi ta đã có markup, ta cần define những gì sẽ xảy ra trong Javascript. Hãy bắt đầu bằng cấp dấu để load trong jQuery quen thuộc:
$(function() { // Module sẽ làm việc trong này });
Ta thực thi các phần gọi tới jQuery object ta cần:
var t = this; t.$header = $('[data-module-init="header"]'); t.$parentMenuItems = t.$header.find('.menu-item-has-children'); // class này do WordPress tạo ra t.$headerBreakpoint = 1024;
Tiếp đến, ta thực hiện loop để với mỗi item chứa sub-menu thì sẽ click vào link a đầu tiên.
for(var i = 0; i < t.$parentMenuItems.length; i++) { // Đây là link <a> đầu tiên chứ không phải link a trong các sub-menu var $trigger = $(t.$parentMenuItems[i]).children().first(); // <a> element // Bình tĩnh kiểm tra xem có tồn tại không đã if($trigger.length > 0) { $trigger.on('click', function (e) { // Mỗi khi click, kiểm tra breakpoint xem có nhỏ hơn trên khung tablet/mobule không if( $(window).width() <= t.$headerBreakpoint ) { // OK, giờ bạn cần tắt không cho click vào link parent e.preventDefault(); // Bạn tìm ngược ra thằng <li> và cho toggle class của mình $(this).parent().toggleClass('menu-item--opened'); // Sau đó vào thằng sub-menu nằm bên cạnh để đẩy cho hiện ra $(this).next('.sub-menu').slideToggle(); } }); } }
Bạn có hiểu đoạn code ở trên không? Tôi nghĩ nó lý giải khá rõ ràng những gì bạn sẽ làm. Nhưng hãy lưu ý, bạn cần test với những gì bạn viết ra, chứ đừng copy-paste nhé.
Thêm style cho module Header Accordion
Phần style của menu ta sẽ không bàn chi tiết ở đây, gợi ý về cách viết như sau cho các class bạn sẽ sử dụng:
.header__menu {} .header__menu > .menu-item-has-children {} .header__menu > .menu-item-has-children > a {} .header__menu > .menu-item-has-children:hover {} /** Trạng thái khi menu được hiển thị ra **/ .header__menu > .menu-item-has-children.menu-item--opened {}
Nếu bạn cần thêm hướng dẫn, đừng ngại đặt câu hỏi nhé.
Giám đốc tại Công ty CP CODE TỐT. Quản lý ngôn ngữ bản địa tiếng Việt tại WordPress. Là tác giả chính tại codetot.net, Khôi muốn ghi lại một sốvấn đề kỹ thuật trong quá trình phát triển các dự án website với khách hàng.