Web 组件拖动功能到滑块

问题描述 投票:0回答:1

我正在使用 Shopify 主题中的此 Web 组件,我需要向其添加拖放功能。目前,在移动设备和桌面上滑动以及按钮一样有效,但我不知道如何让拖动起作用。

控制台日志工作显示更新的位置,但滑块从未移动

class SliderComponent extends HTMLElement {
  constructor() {
    super();
    this.slider = this.querySelector('[id^="Slider-"]');
    this.sliderItems = this.querySelectorAll('[id^="Slide-"]');
    this.enableSliderLooping = false;
    this.currentPageElement = this.querySelector('.slider-counter--current');
    this.pageTotalElement = this.querySelector('.slider-counter--total');
    this.prevButton = this.querySelector('button[name="previous"]');
    this.nextButton = this.querySelector('button[name="next"]');

    if (!this.slider || !this.nextButton) return;

    this.initPages();
    const resizeObserver = new ResizeObserver((entries) => this.initPages());
    resizeObserver.observe(this.slider);

    this.slider.addEventListener('scroll', this.update.bind(this));
    this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
    this.nextButton.addEventListener('click', this.onButtonClick.bind(this));

    this.onDrag = this.onDrag.bind(this);
    this.stopDragging = this.stopDragging.bind(this);

    this.slider.addEventListener('mousedown', this.startDragging.bind(this));

  }

  initPages() {
    this.sliderItemsToShow = Array.from(this.sliderItems).filter((element) => element.clientWidth > 0);
    if (this.sliderItemsToShow.length < 2) return;
    this.sliderItemOffset = this.sliderItemsToShow[1].offsetLeft - this.sliderItemsToShow[0].offsetLeft;
    this.slidesPerPage = Math.floor(
      (this.slider.clientWidth - this.sliderItemsToShow[0].offsetLeft) / this.sliderItemOffset
    );
    this.totalPages = this.sliderItemsToShow.length - this.slidesPerPage + 1;
    this.update();
  }

  resetPages() {
    this.sliderItems = this.querySelectorAll('[id^="Slide-"]');
    this.initPages();
  }

  update() {
    console.log('update');
    // Temporarily prevents unneeded updates resulting from variant changes
    // This should be refactored as part of https://github.com/Shopify/dawn/issues/2057
    if (!this.slider || !this.nextButton) return;

    const previousPage = this.currentPage;
    this.currentPage = Math.round(this.slider.scrollLeft / this.sliderItemOffset) + 1;

    if (this.currentPageElement && this.pageTotalElement) {
      this.currentPageElement.textContent = this.currentPage;
      this.pageTotalElement.textContent = this.totalPages;
    }

    if (this.currentPage != previousPage) {
      this.dispatchEvent(
        new CustomEvent('slideChanged', {
          detail: {
            currentPage: this.currentPage,
            currentElement: this.sliderItemsToShow[this.currentPage - 1],
          },
        })
      );
    }

    if (this.enableSliderLooping) return;

    if (this.isSlideVisible(this.sliderItemsToShow[0]) && this.slider.scrollLeft === 0) {
      this.prevButton.setAttribute('disabled', 'disabled');
    } else {
      this.prevButton.removeAttribute('disabled');
    }

    if (this.isSlideVisible(this.sliderItemsToShow[this.sliderItemsToShow.length - 1])) {
      this.nextButton.setAttribute('disabled', 'disabled');
    } else {
      this.nextButton.removeAttribute('disabled');
    }
  }

  isSlideVisible(element, offset = 0) {
    const lastVisibleSlide = this.slider.clientWidth + this.slider.scrollLeft - offset;
    return element.offsetLeft + element.clientWidth <= lastVisibleSlide && element.offsetLeft >= this.slider.scrollLeft;
  }

  onButtonClick(event) {
    event.preventDefault();
    const step = event.currentTarget.dataset.step || 1;
    this.slideScrollPosition =
      event.currentTarget.name === 'next'
        ? this.slider.scrollLeft + step * this.sliderItemOffset
        : this.slider.scrollLeft - step * this.sliderItemOffset;
    this.setSlidePosition(this.slideScrollPosition);
  }

  setSlidePosition(position) {
    this.slider.scrollTo({
      left: position,
    });
  }

  startDragging(event) {
    event.preventDefault();
    this.startX = event.clientX;
    this.slider.classList.add('dragging');

    document.addEventListener('mousemove', this.onDrag);
    document.addEventListener('mouseup', this.stopDragging);

    console.log('Dragging started');
  }

  onDrag(event) {
    event.preventDefault();
    const dx = event.clientX - this.startX;
    this.slider.scrollLeft -= dx;
    this.startX = event.clientX;

    console.log('Dragging:', dx);
  }

  stopDragging(event) {
    this.slider.classList.remove('dragging');
    document.removeEventListener('mousemove', this.onDrag);
    document.removeEventListener('mouseup', this.stopDragging);

    console.log('Dragging stopped');
  }
}
javascript web-component
1个回答
0
投票

根据评论,人们可能对答案不满意,但使用 Shopify 构建的内容就是解决方案。

constructor
我添加了

    this.isDragging = false;
    this.startX = 0;
    this.scrollStartX = 0;
    this.dragThreshold = 10;
    this.isLinkClickAllowed = true;

    this.addEventListener('mousedown', (e) => this.startDrag(e));
    this.addEventListener('mouseup', (e) => this.stopDrag(e));
    this.addEventListener('mouseleave', (e) => this.stopDrag(e));
    this.addEventListener('mousemove', (e) => this.onDrag(e));
    this.addEventListener('click', (e) => this.onClick(e), true);  

然后将这些方法添加到comp:

/**
   * Handles the start of a drag event.
   * @param {MouseEvent} e
   */
  startDrag(e) {
    e.preventDefault();
    this.isDragging = true;
    this.startX = e.pageX;
    this.scrollStartX = this.slider.scrollLeft;
    this.isLinkClickAllowed = true;
  }

  /**
   * Handles the drag event.
   * @param {MouseEvent} e
   */
  onDrag(e) {
    if (!this.isDragging) return;
    e.preventDefault();
    const currentX = e.pageX;
    const dx = currentX - this.startX;

    // If we've dragged past a certain threshold, don't allow the click.
    if (Math.abs(dx) > this.dragThreshold) {
      this.isLinkClickAllowed = false;
    }

    this.slider.scrollLeft = this.scrollStartX - dx;
  }
  /**
   * Resets the isDragging state.
   * @param {MouseEvent} e
   */
  stopDrag(e) {
    this.isDragging = false;
  }
  /**
   * Prevents the click event from firing if the interaction was a drag.
   * @param {MouseEvent} e
   */
  onClick(e) {

    if (!this.isLinkClickAllowed) {
      e.preventDefault();
      e.stopPropagation();
      this.isLinkClickAllowed = true;
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.