Сдвигающийся блок в мобильном
К написанию данного кода меня сподвигла вёрстка мобильной страницы корзины интернет-магазина.
Вынужденное решение для тестового проекта
В верстке нужно было реализовать сдвигающийся блок позиции / товара, для того, чтоб его можно было убрать / удалить из корзины.
Далее на CODEPEN написал простую вёрстку, демонстрирующую страницу корзины с элементами / блоками.
HTML код и CSS стили
<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>.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"
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
В дальнейшем доработал код в событиях убирания пальца или отпускания клавиши мыши. Мне нужно было, чтоб всё-же блок вставал на нужную позицию (либо смещен, либо нет). Иначе блок некрасиво оставался слегка сдвинут при прокрутке экрана вниз. А то неаккуратно.
Посмотреть проект