Hiển thị các bài đăng có nhãn Fancybox - Swiper - Zoomin. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Fancybox - Swiper - Zoomin. Hiển thị tất cả bài đăng

Chủ Nhật, 9 tháng 8, 2026

Fancybox - Swiper - Zoomin


- Demo : ketsathalan

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Product Gallery Zoom & Fancybox</title>

  <!-- Swiper CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
  <!-- Fancybox CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css" />

  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: Arial, sans-serif;
      padding: 40px;
      background-color: #f5f5f5;
    }

    .product-gallery-wrapper {
      display: flex;
      gap: 20px;
      max-width: 1000px;
      margin: 0 auto;
      position: relative;
    }

    /* Container bên trái chứa Ảnh lớn + Thumbnails */
    .gallery-left {
      width: 450px;
      position: relative;
    }

    /* Khung ảnh chính */
    .main-image-container {
      width: 100%;
      height: 450px;
      border: 1px solid #ddd;
      position: relative;
      overflow: hidden;
      cursor: pointer;
      background: #fff;
    }

    .main-image-container img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }

    /* Khung Lens di chuyển trên ảnh chính */
    .zoom-lens {
      position: absolute;
      width: 150px;
      height: 150px;
      border: 1px solid #999;
      background-color: rgba(255, 255, 255, 0.4);
      display: none;
      pointer-events: none; /* Cho phép click xuyên qua lens */
    }

    /* Khung hiển thị Zoom kết quả (Bên phải) */
    .zoom-result {
      position: absolute;
      top: 0;
      left: 470px; /* Nằm ngay cạnh gallery-left */
      width: 450px;
      height: 450px;
      border: 1px solid #ccc;
      background-repeat: no-repeat;
      background-color: #fff;
      display: none;
      z-index: 99;
      box-shadow: 0 4px 10px rgba(0,0,0,0.15);
    }

    /* Slider ảnh thu nhỏ (Thumbnails) */
    .thumb-slider-container {
      margin-top: 15px;
      position: relative;
      padding: 0 30px; /* Dành khoảng trống cho nút Prev/Next */
    }

    .swiper-slide {
      border: 2px solid transparent;
      border-radius: 4px;
      overflow: hidden;
      cursor: pointer;
      height: 70px;
      opacity: 0.7;
      transition: all 0.2s ease;
    }

    .swiper-slide-thumb-active,
    .swiper-slide:hover {
      border-color: #d71921;
      opacity: 1;
    }

    .swiper-slide img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    /* Nút di chuyển Prev / Next */
    .swiper-button-next,
    .swiper-button-prev {
      width: 24px;
      height: 24px;
      color: #333;
    }

    .swiper-button-next::after,
    .swiper-button-prev::after {
      font-size: 14px;
      font-weight: bold;
    }

    .swiper-button-prev { left: 0; }
    .swiper-button-next { right: 0; }
  </style>
</head>
<body>

  <div class="product-gallery-wrapper">
    <!-- Cột bên trái: Ảnh chính & Slider thu nhỏ -->
    <div class="gallery-left">
      <!-- Ảnh chính -->
      <div class="main-image-container" id="mainImgContainer">
        <div class="zoom-lens" id="zoomLens"></div>
        <img id="mainImage" src="https://picsum.photos/id/1018/1000/1000" alt="Sản phẩm chính">
      </div>

      <!-- Thumbnails Carousel (Swiper) -->
      <div class="thumb-slider-container">
        <div class="swiper thumbSwiper">
          <div class="swiper-wrapper">
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1018/1000/1000" alt="Ảnh 1">
            </div>
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1015/1000/1000" alt="Ảnh 2">
            </div>
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1019/1000/1000" alt="Ảnh 3">
            </div>
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1025/1000/1000" alt="Ảnh 4">
            </div>
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1039/1000/1000" alt="Ảnh 5">
            </div>
            <!-- Ảnh thứ 6 và 7 để kích hoạt chuyển slider -->
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1043/1000/1000" alt="Ảnh 6">
            </div>
            <div class="swiper-slide">
              <img src="https://picsum.photos/id/1050/1000/1000" alt="Ảnh 7">
            </div>
          </div>
        </div>
        <!-- Nút điều hướng -->
        <div class="swiper-button-next"></div>
        <div class="swiper-button-prev"></div>
      </div>
    </div>

    <!-- Khung hiển thị Zoom bên phải -->
    <div class="zoom-result" id="zoomResult"></div>
  </div>

  <!-- Swiper JS -->
  <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
  <!-- Fancybox JS -->
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.umd.js"></script>

  <script>
    // 1. Cấu hình Swiper Slider cho thumbnails (Hiển thị 5 ảnh, vượt quá 5 sẽ scroll/next)
    const swiper = new Swiper('.thumbSwiper', {
      slidesPerView: 5,
      spaceBetween: 8,
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });

    const mainImgContainer = document.getElementById('mainImgContainer');
    const mainImage = document.getElementById('mainImage');
    const zoomLens = document.getElementById('zoomLens');
    const zoomResult = document.getElementById('zoomResult');
    const slides = document.querySelectorAll('.thumbSwiper .swiper-slide');

    // Mặc định active slide đầu tiên
    slides[0].classList.add('swiper-slide-thumb-active');

    // Danh sách URL ảnh dùng cho Fancybox
    let galleryItems = Array.from(slides).map(slide => {
      return { src: slide.querySelector('img').src, type: "image" };
    });

    let currentActiveIndex = 0;

    // 2. Chuyển đổi ảnh chính khi click vào thumbnail
    slides.forEach((slide, index) => {
      slide.addEventListener('click', () => {
        document.querySelector('.swiper-slide-thumb-active')?.classList.remove('swiper-slide-thumb-active');
        slide.classList.add('swiper-slide-thumb-active');
        
        currentActiveIndex = index;
        mainImage.src = slide.querySelector('img').src;
        updateZoomBackground();
      });
    });

    // 3. Xử lý hiệu ứng Zoom khi Hover chuột
    function updateZoomBackground() {
      zoomResult.style.backgroundImage = `url('${mainImage.src}')`;
    }
    updateZoomBackground();

    mainImgContainer.addEventListener('mouseenter', () => {
      zoomLens.style.display = 'block';
      zoomResult.style.display = 'block';
      
      // Tính toán tỷ lệ zoom dựa trên kích thước thực tế của ảnh
      const cx = zoomResult.offsetWidth / zoomLens.offsetWidth;
      const cy = zoomResult.offsetHeight / zoomLens.offsetHeight;
      
      zoomResult.style.backgroundSize = `${mainImage.width * cx}px ${mainImage.height * cy}px`;
    });

    mainImgContainer.addEventListener('mouseleave', () => {
      zoomLens.style.display = 'none';
      zoomResult.style.display = 'none';
    });

    mainImgContainer.addEventListener('mousemove', moveLens);

    function moveLens(e) {
      e.preventDefault();
      const rect = mainImgContainer.getBoundingClientRect();
      
      // Lấy tọa độ chuột tương đối trong khung ảnh
      let x = e.clientX - rect.left - (zoomLens.offsetWidth / 2);
      let y = e.clientY - rect.top - (zoomLens.offsetHeight / 2);

      // Giới hạn không cho lens ra ngoài khung ảnh
      if (x > mainImgContainer.offsetWidth - zoomLens.offsetWidth) {
        x = mainImgContainer.offsetWidth - zoomLens.offsetWidth;
      }
      if (x < 0) { x = 0; }
      if (y > mainImgContainer.offsetHeight - zoomLens.offsetHeight) {
        y = mainImgContainer.offsetHeight - zoomLens.offsetHeight;
      }
      if (y < 0) { y = 0; }

      zoomLens.style.left = x + 'px';
      zoomLens.style.top = y + 'px';

      // Tính tỷ lệ và di chuyển background của ô zoom kết quả
      const cx = zoomResult.offsetWidth / zoomLens.offsetWidth;
      const cy = zoomResult.offsetHeight / zoomLens.offsetHeight;

      zoomResult.style.backgroundPosition = `-${x * cx}px -${y * cy}px`;
    }

    // 4. Xử lý Click vào ảnh chính để mở Fancybox Lightbox
    mainImgContainer.addEventListener('click', () => {
      Fancybox.show(galleryItems, {
        startIndex: currentActiveIndex
      });
    });
  </script>
</body>
</html>