23/05/2024

Bấm liên kết scroll trong trang như thế nào?

Khi bạn có các liên kết trong trang và muốn tạo ra 1 menu nội bộ, ta có thể sử dụng jQuery để tạo ra hiệu ứng scroll mượt trong trang. Bài viết này sử dụng jQuery để các bạn có thể làm theo dễ dàng.

Mục lục bài viết

Mô tả vấn đề

  • Liên kết nội bộ trong trang sẽ có dạng “#san-pham”, “#bao-gia”.
  • Khi bấm vào liên kết, scroll chậm (không bị giật) xuống từng phần tương ứng.

Trình duyệt hiện đại cũng có cung cấp phương thức này, tuy nhiên cần tính đến khả năng người dùng sử dụng code cũ hơn, và bản thân bạn vẫn phải viết event để tương tác.

document.getElementById("bao-gia").scrollIntoView({ 
  behavior: 'smooth' 
});

Keyword bạn có thể tham khảo bằng tiếng Anh: JS Scroll into view nhé.

Test Case cần tính đến:

  • Trên cùng khu vực liên kết menu sẽ có cả 2 dạng menu nội bộ và menu bên ngoài (bấm mở tab mới).
  • Khi bấm vào liên kết, có hiệu ứng scroll chậm xuống không.
  • Khi bấm vào liên kết, vị trí scroll có đúng ở đầu mép màn hình (và không bị che khuất bởi header của web không)
  • Giả sử thành phần cần scroll đến không tồn tại, liệu có gây ra lỗi không.

Hướng xử lý

HTML dự kiến sẽ sử dụng thuộc tính target của liên kết để phân biệt đâu là liên kết trong hay ngoài.

<ul class="scroll-menu">
  <li><a href="#san-pham" target="_self">Sản phẩm</a></li>
  <li><a href="#bao-gia" target="_self">Báo giá</a></li>
  <li><a href="http://chuyendev.com" target="_blank">Code bởi CHUYÊN DEV</a></li>
</ul>

Markup HTML của các section tương ứng:

<section id="san-pham"></section>
<section id="bao-gia"></section>

Tiếp theo, ta xử lý về code Javascript. Mình sử dụng nhanh jQuery để có luôn hiệu ứng animation scroll.

jQuery('.scroll-menu li a[href*="#"]').bind('click', function(e) {
    var target = jQuery(this).attr('href)
    var targetType = jQuery(this).attr('target')
    var headerHeight = jQuery('.scroll-menu').height()

    if ('_self' !== targetType) {
      return false
    }

    e.preventDefault()

    // Case 2: Nếu link chứa https, coi như 1 liên kết ngoài
    if (target.indexOf('http') !== -1){
         window.location.href = target

         return true
    }

    // Final: Tiến hành scroll xuống
    jQuery('html, body').stop().animate({
        scrollTop: jQuery(target).offset().top + headerHeight - 200
    }, 500)

    return false
})

Bên trên là code tham khảo cho phần scroll xuống. Giờ bạn muốn tạo ra hiệu ứng active (vd đổi màu cho link tương ứng đã bấm) thì làm như thế nào? Mình sẽ gán class is-active vào thẻ <li> của mỗi đối tượng đang được scroll đến.

:root {
  --bs-dark: #333;
  --bs-danger: #ff0000;
}

.scroll-menu li a { color: var(--bs-dark); }
.scroll-menu li.is-active a { color: var(--bs-danger); }

Và đây là code Javascript tham khảo để khi scroll tới đâu thì trạng thái active sẽ có tới đó.

jQuery(window).scroll(function() {
    var scrollDistance = jQuery(window).scrollTop() + 300
    var ACTIVE_CLASS = 'is-active'
    
    jQuery('section [id*="#"]').each(function() {
        var sectionId = '#' + jQuery(this).attr('id')
        if (jQuery(this).position().top <= scrollDistance ) {
            jQuery('.scroll-menu li.is-active').removeClass(ACTIVE_CLASS)
            jQuery('.scroll-menu li a').each(function() {
                if (jQuery(this).attr('href') == sectionId) {
                    jQuery(this).parent().addClass(ACTIVE_CLASS)

                    var position = jQuery(this).parent().position().left

                    jQuery('.scroll-menu').scrollLeft(position)
                }
            })
        }
    })
})
5/5 - (1 bình chọn)