Search code examples
javascriptevent-handlingclickmousemove

javascript stop click event on mousemove


i have a draggable parent with click events on the children. i want to cancel/abort/stop the click event of the child when it's starting to get dragged, but also don't want do stop any parent events. Since i don't use a lot of jQuery, i'd be very thankful for a vanilla javascript solution.

sorry for this newbie question, but i can't wrap my head around it.

here is what i got so far: JSFiddle

// horizontal drag scroll for items
const itemScroll = document.querySelector('#itemScroll');
var isDown = false;
var startX;
var scrollLeft;

itemScroll.addEventListener('mousedown', (e) => {
  isDown = true;
  itemScroll.classList.add('active');
  startX = e.pageX - itemScroll.offsetLeft;
  scrollLeft = itemScroll.scrollLeft;
});
itemScroll.addEventListener('mouseleave', () => {
  isDown = false;
  itemScroll.classList.remove('active');
});
itemScroll.addEventListener('mouseup', () => {
  isDown = false;
  itemScroll.classList.remove('active');
});
itemScroll.addEventListener('mousemove', (e) => {
  if (!isDown) return;
  e.preventDefault();
  const x = e.pageX - itemScroll.offsetLeft;
  itemScroll.scrollLeft = scrollLeft - (x - startX);
});

// click an item to change bg-color
const items = document.querySelectorAll('.item');

for (var i = 0; i < items.length; i++) {
  items[i].addEventListener('click', function (e) {
    this.classList.toggle('active');
  });
}

Solution

  • Detect movement and in that case "prevent" the default click behaviour programmatically using a global variable. We reset the is_moved variable when mousedown, and set it when mousemove.

    // horizontal drag scroll for items
    const itemScroll = document.querySelector('#itemScroll');
    var isDown = false;
    var startX;
    var scrollLeft;
    var isMoved = false;
    
    itemScroll.addEventListener('mousedown', (e) => {
      isDown = true;
      isMoved = false;
      itemScroll.classList.add('active');
      startX = e.pageX - itemScroll.offsetLeft;
      scrollLeft = itemScroll.scrollLeft;
    });
    itemScroll.addEventListener('mouseleave', () => {
      isDown = false;
      itemScroll.classList.remove('active');
    });
    itemScroll.addEventListener('mouseup', () => {
      isDown = false;
      itemScroll.classList.remove('active');
    });
    itemScroll.addEventListener('mousemove', (e) => {
      if (!isDown) return;
      isMoved = true;
      e.preventDefault();
      const x = e.pageX - itemScroll.offsetLeft;
      itemScroll.scrollLeft = scrollLeft - (x - startX);
    });
    
    // click an item to change bg-color
    const items = document.querySelectorAll('.item');
    
    for (var i = 0; i < items.length; i++) {
      items[i].addEventListener('click', function(e) {
        if (!isMoved) {
          this.classList.toggle('active');
        }
      });
    }
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    .mainCont {
      width: 100%;
      max-width: 100vw;
      height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      scroll-snap-align: center;
    }
    
    #itemScroll {
      cursor: pointer;
      overflow-x: hidden;
    }
    
    #itemScroll.active {
      cursor: grabbing;
    }
    
    .itemRow {
      width: max-content;
      min-width: 100%;
      height: 100%;
      max-height: 400px;
      padding: 0 5vw;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      gap: 5rem;
      transform-style: preserve-3d;
    }
    
    .item {
      width: 100px;
      height: 100px;
      max-width: 400px;
      max-height: 100%;
      background-color: red;
    }
    
    .item.active {
      background-color: green;
    }
    <div class="mainCont" id="itemScroll">
      <div class="itemRow">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
      </div>
    </div>