Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> HTML

Kéo thả làm mới (Pull to Refresh) trên trình duyệt mobile web

Tính năng "Pull to Refresh" (kéo xuống để làm mới) phổ biến trên app native, có thể triển khai trên mobile web bằng JavaScript + Touch Events.

Cơ chế hoạt động

  1. Lắng nghe touchstart, touchmove, touchend trên container cuộn.
  2. Khi cuộn lên trên cùng (scrollTop === 0) và kéo tiếp xuống (touchmove Y tăng) → hiển thị indicator "Kéo để làm mới".
  3. Khi thả (touchend) nếu kéo đủ ngưỡng → trigger callback (gọi API, reload data).
  4. Animation mượt: CSS transform/transition cho indicator.

Triển khai đơn giản (Vanilla JS)

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    .pull-refresh {
      position: fixed;
      top: -60px;
      left: 0;
      right: 0;
      height: 60px;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #f5f5f5;
      border-bottom: 1px solid #ddd;
      transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
      z-index: 100;
      font-size: 14px;
      color: #666;
    }
    .pull-refresh.visible { transform: translateY(60px); }
    .pull-refresh.loading { color: #007bff; }
    .content { padding-top: 60px; min-height: 100vh; }
  </style>
</head>
<body>
  <div class="pull-refresh" id="pullRefresh">Kéo xuống để làm mới</div>
  <div class="content" id="scrollContainer">
    <!-- Nội dung dài -->
    <div style="height: 2000px; padding: 20px;">Nội dung trang...</div>
  </div>

  <script>
    var pullRefresh = document.getElementById('pullRefresh');
    var container = document.getElementById('scrollContainer');
    var startY = 0;
    var pulling = false;
    var threshold = 60; // px

    container.addEventListener('touchstart', function(e) {
      if (container.scrollTop === 0) {
        startY = e.touches[0].clientY;
        pulling = true;
      }
    }, { passive: true });

    container.addEventListener('touchmove', function(e) {
      if (!pulling) return;
      var deltaY = e.touches[0].clientY - startY;
      if (deltaY > 0) {
        e.preventDefault(); // Ngăn scroll mặc định
        var pullDistance = Math.min(deltaY * 0.5, threshold * 1.5); // Resistance
        pullRefresh.style.transform = 'translateY(' + (-threshold + pullDistance) + 'px)';
        pullRefresh.classList.toggle('visible', pullDistance > threshold * 0.5);
        pullRefresh.textContent = pullDistance > threshold ? 'Thả để làm mới' : 'Kéo xuống để làm mới';
      }
    }, { passive: false });

    container.addEventListener('touchend', function() {
      if (!pulling) return;
      pulling = false;
      
      var currentTransform = pullRefresh.style.transform;
      var pulled = currentTransform ? parseFloat(currentTransform.split('(')[1]) : 0;
      
      if (pulled >= 0) { // Kéo đủ ngưỡng
        pullRefresh.classList.add('loading');
        pullRefresh.textContent = 'Đang làm mới...';
        pullRefresh.style.transform = 'translateY(0)';
        
        // Gọi API reload data
        setTimeout(function() {
          // location.reload(); // Hoặc fetch data mới
          pullRefresh.classList.remove('visible', 'loading');
          pullRefresh.style.transform = 'translateY(-60px)';
          pullRefresh.textContent = 'Kéo xuống để làm mới';
        }, 1500);
      } else {
        // Quay về vị trí ẩn
        pullRefresh.style.transform = 'translateY(-60px)';
        pullRefresh.classList.remove('visible');
      }
    });
  </script>
</body>
</html>

Thư viện sẵn có (Khuyên dùng Production)

  • PullToRefresh.js - Nhẹ, không dependency, customizable.
  • iscroll - Scroll engine có sẵn pull-to-refresh (Twitter từng dùng).
  • Swiper.js - Slider có built-in pull-to-refresh.
  • Framework7, Ionic - UI framework mobile có sẵn component.

Lưu ý UX

  • Chỉ bật trên trang danh sách (list/feed), không phải trang chi tiết/form.
  • Indicator rõ ràng: icon mũi tên xoay, text hướng dẫn, loading spinner.
  • Haptic feedback (navigator.vibrate) khi đạt ngưỡng (nếu hỗ trợ).
  • Accessibility: ARIA live region cho screen reader.

Native Browser Pull-to-Refresh

Chrome Android / Safari iOS có pull-to-refresh mặc định trên body. Để tắt (xem bài "Vô hiệu hóa pull-to-refresh Chrome Android"):

body { overscroll-behavior-y: contain; }