Сдвигающийся блок в мобильном

К написанию данного кода меня сподвигла вёрстка мобильной страницы корзины интернет-магазина.

Вынужденное решение для тестового проекта

В верстке нужно было реализовать сдвигающийся блок позиции / товара, для того, чтоб его можно было убрать / удалить из корзины.

Далее на CODEPEN написал простую вёрстку, демонстрирующую страницу корзины с элементами / блоками.

HTML код и CSS стили

HTML
<div class="page flex flex-center">
  <div class="box">
    <div class="container">
        
      <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
        <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
        <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
        <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
        <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
        <div class="card" data-pos="0">
        <div class="card__inner">
          <div class="image"></div>
          <div class="content">
            <div class="line"></div>
            <div class="line"></div>
          </div>
        </div>
      </div>
        
    </div>
  </div>
</div>
CSS
.box{
  width: 400px;
  height: 700px;
  border-radius: 8px;
  border: 1px solid rgb(0 0 0 / 0.2);
  padding-top: 32px;
  padding-bottom: 32px;
  overflow: hidden;
}
.card{
  margin-bottom: 8px;
  padding: 8px;
  border-radius: 8px;
  border: 1px solid rgb(0 0 0 / 0.2);
  cursor: pointer;
  background-color: #fff;
  transition: translate 50ms linear;
  &__inner{
    display: flex;
    gap: 16px;
  }
  .image{
    background-color: #eee;
    height: 80px;
    width: 80px;
    border-radius: 100%;
  }
  .line{
    height: 26px;
    background-color: #eee;
    margin-bottom: 16px;
    &:last-child{
      margin-bottom: 0;
      width: 50%;
    }
  }
  .content {
    flex-grow: 1;
  }
}

После написания разметки принялся за добавление JS

Долго не мог сообразить, почему каждый раз перескакивает сам блок, при новом нажатии на него. Проблема была в неправильном расчете (не учитывалось начальное местоположение блока перед нажатием). Решено с помощью добавления блоку атрибута data-pos="0"

JavaScript
document.addEventListener(
    "dragstart",
    function (e) {
        e.preventDefault();
    },
    false
);
let cards = document.querySelectorAll(".card");

cards.forEach((el) => {
//     !!! MOUSE EVENTS START --------------
    el.onmousedown = function (e) {
        let cardStartPos = +el.dataset['pos'];
        let startX = e.clientX;
        let delta = 0;
        
        el.onmousemove = function (e) {
            delta = e.clientX - startX;
            
            this.style.translate = `${cardStartPos + delta}px`;
            let cardLastPos = cardStartPos + delta;
            
            if (cardStartPos + delta < -100) {
                this.style.translate = `-100px`;
                cardLastPos = -100;
                el.onmousemove = "";
            }
            
            if (cardStartPos + delta > 0) {
                this.style.translate = `0px`;
                cardLastPos = 0;
                el.onmousemove = "";
            }

            el.onmouseleave = function (e) {
                if(cardLastPos > -50 && cardLastPos < 0){
                    this.style.translate = `0px`;
                    cardLastPos = 0;
                }else if(cardLastPos > -100 && cardLastPos < -50){
                    this.style.translate = `-100px`;
                    cardLastPos = -100;
                }
                el.dataset['pos'] = cardLastPos;
                el.onmousemove = "";
                el.onmouseup = "";
            };

            el.onmouseup = function (e) {
                if(cardLastPos > -50 && cardLastPos < 0){
                    this.style.translate = `0px`;
                    cardLastPos = 0;
                }else if(cardLastPos > -100 && cardLastPos < -50){
                    this.style.translate = `-100px`;
                    cardLastPos = -100;
                }
                el.dataset['pos'] = cardLastPos;
                el.onmouseleave = "";
                el.onmousemove = "";
                
            };
        };
    };
//     !!! MOUSE EVENTS END -----------------
    
//     !!! TOUCH EVENTS START ---------------
    el.ontouchstart = function (e) {
        let cardStartPos = +el.dataset['pos'];
        let startX = e.touches[0].clientX;
        let delta = 0;
        
        el.ontouchmove = function (e) {
            delta = e.touches[0].clientX - startX;

            this.style.translate = `${cardStartPos + delta}px`;
            let cardLastPos = cardStartPos + delta;
            
            if (cardStartPos + delta < -100){
                this.style.translate = `-100px`;
                cardLastPos = -100;
                el.ontouchmove = "";
            }
             if (cardStartPos + delta > 0) {
                this.style.translate = `0px`;
                cardLastPos = 0;
                el.ontouchmove = "";
            }

            el.ontouchend = function (e) {
                if(cardLastPos > -50 && cardLastPos < 0){
                    this.style.translate = `0px`;
                    cardLastPos = 0;
                }else if(cardLastPos > -100 && cardLastPos < -50){
                    this.style.translate = `-100px`;
                    cardLastPos = -100;
                }
                el.dataset['pos'] = cardLastPos;
                el.ontouchmove = "";
            };
        };
    };
//     !!! TOUCH EVENTS END ----------------
});

Кстати говоря, в JS код вставлен небольшой костыль в виде отключения прослушивателя события dragstart

В дальнейшем доработал код в событиях убирания пальца или отпускания клавиши мыши. Мне нужно было, чтоб всё-же блок вставал на нужную позицию (либо смещен, либо нет). Иначе блок некрасиво оставался слегка сдвинут при прокрутке экрана вниз. А то неаккуратно.

Посмотреть проект