shopline详情页主图自动轮播

其他都不用修改,只改component-media-gallery,js
效果图为:在这里插入图片描述

defineCustomElement('media-gallery', () => {
    return class MediaGallery extends HTMLElement {
      constructor() {
        super();
        this.elements = {
          viewer: this.querySelector('[id^="GalleryViewer"]'),
          thumbnails: this.querySelector('[id^="GalleryThumbnails"]'),
        };
        this.mql = window.matchMedia('(min-width: 750px)');
        this.mediaVideoAutoPlay = this.getAttribute('data-video-autoplay') === 'true';
        this.paginationType = this.getAttribute('data-pagination-type');
        this.handleVideoAutoPlay();
        this.initMultiStylesPagination();
  
        this.autoPlayInterval = null;
        this.autoPlayDuration = 3000; // 设置自动轮播的时间间隔,单位为毫秒
  
        this.elements.viewer.addEventListener('slideChanged', window.debounce(this.onSlideChanged.bind(this), 300));
  
        if (!this.elements.thumbnails) return;
        this.elements.thumbnails.querySelectorAll('[data-target]').forEach((mediaToSwitch) => {
          mediaToSwitch
            .querySelector('button')
            .addEventListener('click', this.setActiveMedia.bind(this, mediaToSwitch.dataset.target, false));
        });
      }
  
      connectedCallback() {
        document.addEventListener('animationstart', (event) => {
          if (event.animationName === 'galleryLoaded') {
            this.elements.viewer.resetSlides();
          }
        });
        this.startAutoPlay(); // 开始自动轮播
      }
  
      disconnectedCallback() {
        this.stopAutoPlay(); // 停止自动轮播
      }
  
      startAutoPlay() {
        this.stopAutoPlay(); // 清除之前的轮播定时器,避免重复
        this.autoPlayInterval = setInterval(() => {
          const slides = Array.from(this.elements.viewer.querySelectorAll('[id^="Slide-"]'));
          const currentIndex = slides.findIndex((slide) => slide.classList.contains('is-active'));
  
          // 确定下一个要显示的幻灯片索引,如果到最后一张则回到第一张
          const nextIndex = (currentIndex + 1) % slides.length;
  
          // 移除当前的 is-active 类,并添加到下一个幻灯片上
          slides[currentIndex].classList.remove('is-active');
          slides[nextIndex].classList.add('is-active');
  
          // 更新缩略图和分页
          this.setActiveThumbnail(slides[nextIndex].dataset.mediaId);
          this.setActiveMultiStylesPagination(nextIndex + 1);
        }, this.autoPlayDuration);
      }
  
      stopAutoPlay() {
        if (this.autoPlayInterval) {
          clearInterval(this.autoPlayInterval);
          this.autoPlayInterval = null;
        }
      }
  
      onSlideChanged(event) {
        const { currentElement, currentPage } = event.detail;
        this.setActiveThumbnail(currentElement.dataset.mediaId);
        this.setActiveMultiStylesPagination(currentPage);
      }
  
      setActiveMultiStylesPagination(currentPage = 1) {
        const mobileQl = window.matchMedia('(max-width: 959px)');
  
        const PROGRESS = 'progress';
        const DOT = 'dot';
        const SLIDER_BAR = 'slider-bar';
        const extraPaginationType = [PROGRESS, DOT, SLIDER_BAR];
        if (!mobileQl.matches || !extraPaginationType.includes(this.paginationType)) return;
  
        const totalPage = this.elements.viewer._getTotalPage();
  
        if (!totalPage || !currentPage) return;
  
        if (this.paginationType === PROGRESS) {
          const progressElement = this.querySelector('.product-pagination__progress');
          const widthPercent = ((currentPage / totalPage) * 100).toFixed(3);
  
          progressElement.style.setProperty('--progress-percent', `${widthPercent}%`);
        } else if (this.paginationType === DOT || SLIDER_BAR) {
          const dotElements = this.querySelectorAll('.product-pagination__dot-slider .tap-area');
  
          dotElements.forEach((element, index) => {
            element.removeAttribute('data-current');
            element.classList.remove('display-block', 'display-none');
            if (index < totalPage) {
              element.classList.add('display-block');
            } else {
              element.classList.add('display-none');
            }
            if (index === currentPage - 1) {
              element.setAttribute('data-current', true);
            }
          });
        }
      }
  
      initMultiStylesPagination() {
        window.setTimeout(() => {
          const { currentPage } = this.elements.viewer;
          this.setActiveMultiStylesPagination(currentPage);
        });
      }
  
      handleRemoveNotSelectedVariantStatus() {
        const INIT_CLASS = 'js-init-not-selected-variant';
        const { sectionId } = this.dataset;
        const productModal = document.querySelector(`#ProductModal-${sectionId}`);
        if (this.classList.contains(INIT_CLASS)) {
          this.classList.remove(INIT_CLASS);
          window.setTimeout(() => {
            this.setActiveMultiStylesPagination();
          });
        }
        if (productModal && productModal.classList.contains(INIT_CLASS)) {
          productModal.classList.remove(INIT_CLASS);
        }
      }
  
      setActiveMedia(mediaId, prepend) {
        const activeMedia = this.elements.viewer.querySelector(`[data-media-id="${mediaId}"]`);
        const activeMediaIndex = Array.from(activeMedia.parentElement.children).indexOf(activeMedia);
        const isMobile = window.isMobileScreen();
  
        const pcStyle = this.getAttribute('data-desktop-layout');
        const hideVariants = this.getAttribute('data-hide-variants') === 'true';
        const pcIsSlider = pcStyle === 'thumbnail_flatten' || pcStyle === 'carousel';
        if (pcIsSlider && activeMediaIndex > -1) {
          this.elements.viewer.querySelectorAll('[id^="Slide-"]').forEach((slide, idx) => {
            slide.classList[idx === activeMediaIndex ? 'add' : 'remove']('is-active');
          });
          this.elements.viewer.resetSlides();
        }
  
        if (prepend && (hideVariants || (!isMobile && !pcIsSlider))) {
          activeMedia.parentElement.prepend(activeMedia);
          this.handleRemoveNotSelectedVariantStatus();
          if (this.elements.thumbnails) {
            const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`);
            activeThumbnail.parentElement.prepend(activeThumbnail);
            this.elements.thumbnails.resetSlides();
          }
          if (this.elements.viewer.slider) {
            this.elements.viewer.resetSlides();
            this.elements.viewer.slideTo(1);
          }
        }
  
        window.setTimeout(() => {
          // thumbnails control mobile gallery scroll
          activeMedia.parentElement.scrollTo({
            left: activeMedia.offsetLeft,
          });
  
          // control activeMedia scroll when no thumbnail exists
          const needAutoScrollDesktopLayout = ['flatten', 'columns', 'stacked'];
          if (
            !isMobile &&
            !this.closest('.quick-add-modal__content') &&
            !this.closest('[load-feature-modal]') &&
            (!this.elements.thumbnails || needAutoScrollDesktopLayout.includes(this.dataset.desktopLayout))
          ) {
            const headerLayout = document.body.querySelector('header-layout');
            window.scrollTo({
              top:
                window.scrollY +
                activeMedia.getBoundingClientRect().top -
                (headerLayout.isSticky ? headerLayout.headerLayout.clientHeight : 0),
              behavior: 'smooth',
            });
          }
        });
        this.playActiveMedia(activeMedia);
        // control thumbnails activeMedia scroll
        this.setActiveThumbnail(mediaId);
      }
  
      setActiveThumbnail(activeThumbnailMediaId) {
        if (!this.elements.thumbnails || !activeThumbnailMediaId) return;
        const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${activeThumbnailMediaId}"]`);
  
        this.elements.thumbnails.querySelectorAll('button').forEach((element) => element.removeAttribute('data-current'));
        activeThumbnail.querySelector('button').setAttribute('data-current', true);
        if (this.elements.thumbnails.isSlideVisible(activeThumbnail)) return;
  
        this.elements.thumbnails.slider.scrollTo(
          this.elements.thumbnails.direction === 'vertical'
            ? { top: activeThumbnail.offsetTop }
            : { left: activeThumbnail.offsetLeft },
        );
      }
  
      playActiveMedia(activeItem) {
        window.pauseAllMedia();
        if (!this.mediaVideoAutoPlay) return;
        const deferredMedia = activeItem.querySelector('.deferred-media');
        if (deferredMedia) {
          deferredMedia.loadContent(false);
          deferredMedia.playVideo(false);
        }
      }
  
      handleVideoAutoPlay() {
        const container = document.querySelector(this.getAttribute('data-parent-container'));
  
        const isInViewPort = (element) => {
          const viewWidth = window.innerWidth || document.documentElement.clientWidth;
          const viewHeight = window.innerHeight || document.documentElement.clientHeight;
          const { top, left, right, width, height } = element.getBoundingClientRect();
  
          return width > 0 && height > 0 && top >= 0 && left >= 0 && right <= viewWidth && top <= viewHeight;
        };
  
        const checkDeferredMedia = () => {
          if (this.mediaVideoAutoPlay) {
            const medias = this.elements.viewer.querySelectorAll('.deferred-media');
            medias.forEach((el) => {
              if (isInViewPort(el)) {
                el.loadContent(false);
                el.playVideo();
              }
            });
          }
        };
  
        setTimeout(() => {
          checkDeferredMedia();
        }, 200);
        (container || window).addEventListener('scroll', checkDeferredMedia);
        this.elements.viewer.addEventListener('slideChanged', () => {
          // wait slide finished
          setTimeout(() => {
            checkDeferredMedia();
          }, 200);
        });
      }
    };
  });
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_42456392

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值