Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Как заставить раздельно работать слайдеры с одинаковыми классами? (https://javascript.ru/forum/jquery/77641-kak-zastavit-razdelno-rabotat-slajjdery-s-odinakovymi-klassami.html)

DenKuzmin17 31.05.2019 12:22

Как заставить раздельно работать слайдеры с одинаковыми классами?
 
Есть несколько слайдеров с одинаковыми классами. При взаимодействии с одним, перелисывают все остальные. Как их разделить, сохранив одинаковые классы? Унифицировать каждый слайдер классом или айди - не вариант.

Ссылка на codepen

Malleys 31.05.2019 12:59

https://codepen.io/Malleys/pen/byQjOM?editors=1010 Вам осталось добавить обработку событии клавиатуры!

UPD Добавил обработку событии клавиатуры!

DenKuzmin17 31.05.2019 13:48

Malleys ТОП! Спасибо большое!

DenKuzmin17 31.05.2019 14:29

Подскажите, пожалуйста, как исправить залипание клика? Например, если кликом потяну .slider и курсор уйдёт за пределы .slider-box, то слайдер залипает и начинает двигаться за курсором до следующего клика.
Как сделать, чтобы при выходе курсора за пределы слайда происходил "cancel"?

Malleys 31.05.2019 16:08

Цитата:

Сообщение от DenKuzmin17
Подскажите, пожалуйста, как исправить залипание клика? Например, если кликом потяну .slider и курсор уйдёт за пределы .slider-box, то слайдер залипает и начинает двигаться за курсором до следующего клика.
Как сделать, чтобы при выходе курсора за пределы слайда происходил "cancel"?

Может лучше cancel при отпускании клавиши мыши? https://codepen.io/Malleys/pen/byQjOM?editors=1010

DenKuzmin17 31.05.2019 16:24

Цитата:

Сообщение от Malleys (Сообщение 508583)
Может лучше cancel при отпускании клавиши мыши? https://codepen.io/Malleys/pen/byQjOM?editors=1010

В целом, понятно.

Если как в Вашем примере, то при зажатии слайда и переводе курсора мыши за область окна (например в поле html) и возврате курсора на слайд, слайдер залипает. Так же заметил, что если навести курсор на другие слайдеры, они тоже залипают.

Спасибо большое за помощь!:thanks:

Malleys 31.05.2019 17:08

DenKuzmin17, проверьте ещё раз, я должно быть не сохранил пример, хотя там стоит автосохранение... (или вы посмотрели в тот момент, когда я что-то менял)

DenKuzmin17 31.05.2019 18:14

Цитата:

Сообщение от Malleys (Сообщение 508585)
DenKuzmin17, проверьте ещё раз, я должно быть не сохранил пример, хотя там стоит автосохранение... (или вы посмотрели в тот момент, когда я что-то менял)

Действительно. Сейчас всё отлично работает. Спасибо большое!:thanks:

рони 31.05.2019 18:20

Цитата:

Сообщение от DenKuzmin17
Как заставить раздельно работать слайдеры с одинаковыми классами?

как вариант,в цикле назначить свои параметры каждому слайдеру.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Malleys JQuery Touch Slider</title>
<style>
            * {
    margin: 0;
    padding: 0;
}
section {
    width: 100%;
    height: 100vh;
    background: #ececec;
}
.block {
    width: 500px;
    height: 100px;
    margin: 10px auto;
}
.slider-box {
    display: flex;
    overflow: hidden;
    border: 1px solid #909090;
}
.slider {
    display: flex;
    transition: 0.5s;
}
.slide {
    display: flex;
    width: 500px;
    height: 100px;
    align-items: center;
    justify-content: center;
}

/* :focus:hover {
    outline: none;
} */
        </style>

</head>
<body translate="no">
<section>
<div class="block 1">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 3</div>
<div class="slide">2 / 3</div>
<div class="slide">3 / 3</div>
</div>
</div>
</div>
<hr>
<div class="block 2">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 4</div>
<div class="slide">2 / 4</div>
<div class="slide">3 / 4</div>
<div class="slide">4 / 4</div>
</div>
</div>
</div>
<hr>
<div class="block 3">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 2</div>
<div class="slide">2 / 2</div>
</div>
</div>
</div>
<hr>
</section>
<script src='https://profforma.store/assets/js/jquery.min.js'></script>
<script src='https://profforma.store/assets/js/jquery.touchSwipe.min.js'></script>
<script>



$(function() {
    $('.slider').each(function() {
        var IMG_WIDTH = 500;
        var currentImg = 0;
        var maxImages = 3;
        var speed = 500;
        var slider = $(this);
        var swipeOptions = {
            triggerOnTouchEnd: true,
            swipeStatus: swipeStatus,
            allowPageScroll: "vertical",
            threshold: 75
        };
        slider.swipe(swipeOptions);
        /**
         * Catch each phase of the swipe.
         * move : we drag the div
         * cancel : we animate back to where we were
         * end : we animate to the next image
         */
        function swipeStatus(event, phase, direction, distance) {
            //If we are moving before swipe, and we are going L or R in X mode, or U or D in Y mode then drag.
            if (phase == "move" && (direction == "left" || direction == "right")) {
                var duration = 0;

                if (direction == "left") {
                    scrollImages((IMG_WIDTH * currentImg) + distance, duration);
                } else if (direction == "right") {
                    scrollImages((IMG_WIDTH * currentImg) - distance, duration);
                }

            } else if (phase == "cancel") {
                scrollImages(IMG_WIDTH * currentImg, speed);
            } else if (phase == "end") {
                if (direction == "right") {
                    previousImage();
                } else if (direction == "left") {
                    nextImage();
                }
            }
        }

        function previousImage() {
            currentImg = Math.max(currentImg - 1, 0);
            scrollImages(IMG_WIDTH * currentImg, speed);
        }

        function nextImage() {
            currentImg = Math.min(currentImg + 1, maxImages - 1);
            scrollImages(IMG_WIDTH * currentImg, speed);
        }

        /**
         * Manually update the position of the slider on drag
         */
        function scrollImages(distance, duration) {
            slider.css("transition-duration", (duration / 1000).toFixed(1) + "s");

            //inverse the number we set in the css
            var value = (distance < 0 ? "" : "-") + Math.abs(distance).toString();
            slider.css("transform", "translate(" + value + "px,0)");
        }
    })
});
    </script>
</body>
</html>

рони 31.05.2019 18:31

Цитата:

Сообщение от Malleys
Добавил обработку событии клавиатуры!

а как же это https://idangero.us/swiper/api/#keyboard?

Malleys 31.05.2019 18:55

Цитата:

Сообщение от рони

О, спасибо за такую прекрасную ссылку, а то тот плагин для jQuery с кучей проблем.
Что, это очень сложно построить слайдер, который бы не ломался, когда мышь уводят за его пределы и отпускают? Сотни настроек предлагают, а основной функционал слайдера не могут нормально сделать!

DenKuzmin17 31.05.2019 19:04

как задать translateX через проценты? Если вместо value записываю новую переменную percent, перелистывание работает, а перетаскивание нет.

рони 31.05.2019 19:06

Malleys,
мне сложно понять, что вы пишите.

DenKuzmin17 31.05.2019 19:06

Цитата:

Сообщение от Malleys (Сообщение 508591)
О, спасибо за такую прекрасную ссылку, а то тот плагин для jQuery с кучей проблем. Что, это очень сложно построить слайдер, который бы не ломался, когда мышь уводят за его пределы и отпускают?

для меня, к сожалению, пока что, сложно. Разбираюсь с Вашей помощью. Спасибо большое.

Malleys 31.05.2019 19:08

Цитата:

Сообщение от DenKuzmin17
для меня, к сожалению, пока что, сложно.

Я имел в виду про авторов этих плагинов...

рони 31.05.2019 19:09

Malleys,
попробую спросить снова, можно ли использовать методы плагина для клавиатуры или нет, в данном случае?

рони 31.05.2019 19:09

Цитата:

Сообщение от Malleys
а основной функционал слайдера не могут нормально сделать!

а что там не так?

Malleys 31.05.2019 19:21

Давайте по порядку...

Я использовал этот плагин, поскольку он был указан в скрипте автора, в котором поддержки клавиатуры нет! http://labs.rampinteractive.co.uk/to...mos/index.html

Вы, рони, предложили это https://idangero.us/swiper/demos/

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

И позвольте уж тогда мне предложить... вот готовый слайдер, в котором нет таких багов... https://flickity.metafizzy.co/options.html

Цитата:

Сообщение от DenKuzmin17
как задать translateX через проценты? Если вместо value записываю новую переменную percent, перелистывание работает, а перетаскивание нет.

А вам принципиально важно использовать ту библиотеку или можно заменить, а то я ковырялся там 2 часа, но мне таки не удалось добиться желаемого результата из-за того, что библиотека отменяет в слайдере события focus и mousedown

рони 31.05.2019 19:24

Malleys,
ок! думал плагины одинаковы, исходил из названия.
Цитата:

Сообщение от Malleys
вот готовый слайдер,

спасибо!

Malleys 31.05.2019 19:38

<link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">
<style>
* {
  margin: 0;
  padding: 0;
}
section {
  width: 100%;
  height: 100vh;
  background: #ececec;
}
.block {
  width: 500px;
  height: 100px;
  margin: 10px auto;
}
.slider-box {
  border: 1px solid #909090;
}
.slider {
  transition: 0.5s;
}
.slide {
  display: flex;
  width: 500px;
  height: 100px;
  align-items: center;
  justify-content: center;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>
<script>
	$(function() {
		$('.slider').flickity({
			prevNextButtons: false,
			pageDots: false
		});
	});
</script>

<section>
  <div class="block 1">
    <div class="slider-box">
      <div class="slider">
        <div class="slide">1 / 3</div>
        <div class="slide">2 / 3</div>
        <div class="slide">3 / 3</div>
      </div>
    </div>
  </div>
  <hr>
  <div class="block 2">
    <div class="slider-box">
      <div class="slider">
        <div class="slide">1 / 4</div>
        <div class="slide">2 / 4</div>
        <div class="slide">3 / 4</div>
        <div class="slide">4 / 4</div>
      </div>
    </div>
  </div>
  <hr>
  <div class="block 3">
    <div class="slider-box">
      <div class="slider">
        <div class="slide">1 / 2</div>
        <div class="slide">2 / 2</div>
      </div>
    </div>
  </div>
  <hr>
</section>

рони 31.05.2019 19:44

Malleys,
:thanks:

DenKuzmin17 31.05.2019 19:55

Цитата:

Сообщение от Malleys (Сообщение 508598)
А вам принципиально важно использовать ту библиотеку или можно заменить

Не принципиально. Просто начал уже на этом делать. Мне чем проще тем лучше, желательно вообще без плагинов. Попробую потом то, что Вы предлагает выше.

PS transition в процентах с текущим плагином можно реализовать?

Malleys 31.05.2019 20:32

Цитата:

Сообщение от DenKuzmin17
PS transition в процентах с текущим плагином можно реализовать?

Да, можно! https://codepen.io/Malleys/pen/byQjOM?editors=0010

рони 31.05.2019 21:06

:-?
зачем это
var value = (distance < 0 ? "" : "-") + Math.abs(distance).toString();

вариант без этой строки
scrollImages(distance, duration) {
        this.slider.css("transition-duration", (duration / 1000).toFixed(1) + "s");
        this.slider.css("transform", "translate(" + (100 * -distance / this.maxImages) + "%,0)");
    }

DenKuzmin17 31.05.2019 23:45

this.currentImg + 0.0025 * distance,
          duration
"0.0025" это что?

рони 01.06.2019 00:12

:write: вариант ...
if (direction == "left") {
                this.scrollImages(
                    this.currentImg + distance / this.IMG_WIDTH ,
                    duration
                );
            } else if (direction == "right") {
                this.scrollImages(
                    this.currentImg - distance / this.IMG_WIDTH ,
                    duration
                );
            }

рони 01.06.2019 00:32

:write: всё в сборе ...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Malleys JQuery Touch Slider</title>
<style>
            * {
    margin: 0;
    padding: 0;
}
section {
    width: 100%;
    height: 100vh;
    background: #ececec;
}
.block {
    width: 500px;
    height: 100px;
    margin: 10px auto;
}
.slider-box {
    display: flex;
    overflow: hidden;
    border: 1px solid #909090;
}
.slider {
    display: flex;
    transition: 0.5s;
}
.slide {
    display: flex;
    width: 500px;
    height: 100px;
    align-items: center;
    justify-content: center;
}

/* :focus:hover {
    outline: none;
} */
        </style>

</head>
<body translate="no">
<section>
<div class="block 1">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 3</div>
<div class="slide">2 / 3</div>
<div class="slide">3 / 3</div>
</div>
</div>
</div>
<hr>
<div class="block 2">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 4</div>
<div class="slide">2 / 4</div>
<div class="slide">3 / 4</div>
<div class="slide">4 / 4</div>
</div>
</div>
</div>
<hr>
<div class="block 3">
<div class="slider-box">
<div class="slider">
<div class="slide">1 / 2</div>
<div class="slide">2 / 2</div>
</div>
</div>
</div>
<hr>
</section>
<script src='https://profforma.store/assets/js/jquery.min.js'></script>
<script src='https://profforma.store/assets/js/jquery.touchSwipe.min.js'></script>
<script>



class Slider {
    constructor(slider) {
        this.IMG_WIDTH = 500;
        this.currentImg = 0;
        this.speed = 500;

        this.swipeStatus = this.swipeStatus.bind(this);
        this.keyboardHandler = this.keyboardHandler.bind(this);

        this.slider = $(slider);
        this.slider
            .parent()
            .attr("tabIndex", 0)
            .on("blur focus click", this.keyboardHandler)
            .swipe({
                triggerOnTouchEnd: true,
                triggerOnTouchLeave: true,
                swipeStatus: this.swipeStatus,
                allowPageScroll: "vertical",
                threshold: 75
            });
        this.maxImages = this.slider.find(">*").length;
    }

    keyboardHandler(event) {
        if (event.type === "focus") {
            document.addEventListener("keydown", this.keyboardHandler);
            this.constructor.activeInstance = this;
        } else if (event.type === "blur") {
            document.removeEventListener("keydown", this.keyboardHandler);
            this.constructor.activeInstance = null;
        } else if (event.type === "keydown") {
            if (event.keyCode === 37) this.previousImage();
            if (event.keyCode === 39) this.nextImage();
        } else {
            this.slider.parent().focus();
        }

        return true;
    }

    swipeStatus(event, phase, direction, distance) {
        //If we are moving before swipe, and we are going L or R in X mode, or U or D in Y mode then drag.
        if (phase == "move" && (direction == "left" || direction == "right")) {
            var duration = 0;

            if (direction == "left") {
                this.scrollImages(
                    this.currentImg + distance / this.IMG_WIDTH ,
                    duration
                );
            } else if (direction == "right") {
                this.scrollImages(
                    this.currentImg - distance / this.IMG_WIDTH ,
                    duration
                );
            }
        } else if (phase == "cancel") {
            this.scrollImages(this.currentImg, this.speed);
        } else if (phase == "end") {
            if (direction == "right") {
                this.previousImage();
            } else if (direction == "left") {
                this.nextImage();
            }
        }
    }

    scrollImages(distance, duration) {
        this.slider.css({"transition-duration" : (duration / 1000).toFixed(1) + "s",
                         "transform" : "translate(" + (100 * -distance / this.maxImages) + "%,0)"});
    }

    previousImage() {
        this.currentImg = Math.max(this.currentImg - 1, 0);
        this.scrollImages(this.currentImg, this.speed);
    }

    nextImage() {
        this.currentImg = Math.min(this.currentImg + 1, this.maxImages - 1);
        this.scrollImages(this.currentImg, this.speed);
    }
}

$(() => {
    for (const element of $(".slider")) {
        new Slider(element);
    }
});

    </script>
</body>
</html>

Malleys 01.06.2019 15:07

Цитата:

Сообщение от DenKuzmin17
"0.0025" это что?

Коэффициент, пропорционально которому сдвигается слайд.

Вот, написал собственную реализацию слайдера без той сторонней библиотеки. https://codepen.io/Malleys/pen/byQjOM?editors=0010 Теперь можно начать перетаскивать слайд и курсор мыши вывести за рамки окна браузера и оно правильно обрабатывается! Что-то не нашёл ни одной библиотеки, которые бы это учитывали.

рони 01.06.2019 15:47

Malleys,
зачем эта строка?
this.slider[Symbol.for("slider")] = this;

или как это работает?
pointer.addEventListener("start", ({ target }) => {
    Slider.activeElement = (
    target.matches(".slider") && target ||
    target.closest(".slider") ||
    {})[
    Symbol.for("slider")];
});

не понимаю что тут происходит, зачем нужно использовать Symbol.for("slider")?

Malleys 01.06.2019 16:02

Цитата:

*Malleys*,
зачем эта строка?
<pre class="source brush:js;light:true">
this.slider[Symbol.for("slider")] = this;
</pre>
Чтобы можно было обратиться к представителю класса Slider через элемент, к которому он привязан. Поскольку я определил только одного представителя SinglePointer, и на нём прослушиваются события start, move, end... то через него можно узнать, на каком элементе типа HTMLElement началось перетаскивание... а свойство Symbol.for("slider") помогает получить ссылку на такой слайдер (объект типа Slider), который был инициализирован тем самым элементом, над которым началось перетаскивание.

Цитата:

Сообщение от рони
не понимаю что тут происходит, зачем нужно использовать Symbol.for("slider")?

Сначала находится ближайший элемент с селектором .slider, а затем берётся ссылка на представителя класса Slider, которым этот элемент был инициализирован!

рони 01.06.2019 16:25

Malleys,
ещё вопрос почему на родителя
this.slider.parentNode.addEventListener
а не на элемент slider, ставится обработка событий?

рони 01.06.2019 16:28

Malleys,
в чём смысл уникальной метки this.slider[Symbol.for("slider")] = this;
почему не this.slider["slider"] = this; например?

Malleys 01.06.2019 16:43

Цитата:

Сообщение от рони
в чём смысл уникальной метки this.slider[Symbol.for("slider")] = this;
почему не this.slider["slider"] = this; например?

Интерфейс HTMLElement не подразумевает существование такого свойства. Хотя конечно ничего такого не нужно было бы, если бы Slider наследовал от HTMLElement.

Цитата:

Сообщение от рони
ещё вопрос почему на родителя
this.slider.parentNode.addEventListener
а не на элемент slider, ставится обработка событий?

Как я понял из той разметки, .slider-box является самим элементом слайдера, который может вставляться в любое место. На него я добавил атрибут tabindex, но стоит учитывать, что события focus и blur не вплывают, поэтому обработчики были добавлены на тот же элемент, где был добавлен tabindex.

рони 01.06.2019 16:54

Цитата:

Сообщение от Malleys
Интерфейс HTMLElement не подразумевает существование такого свойства. Хотя конечно ничего такого не нужно было бы, если бы Slider наследовал от HTMLElement.

сложновато, для меня, понять что здесь написано, но спасибо!

DenKuzmin17 03.06.2019 01:09

Цитата:

Сообщение от Malleys (Сообщение 508603)

Супер! Спасибо большое! В последнем варианте слайды снова залипают =(


Часовой пояс GMT +3, время: 13:44.