Как определить момент остановки слайдера-карусели

Есть слайдер с заголовками постов в виде 3d-карусели. Его можно в т.ч. свайпать - он обладает инерцией и слайды, которые проходят через центр его div-а, получают класс .active. Т.е. если крутануть хорошо, он крутится довольно долго и за это время много слайдов, становятся на какое-то время “центральными” (активными). Мне же нужно получить самый последний активный слайд, когда слайдер остановится, чтобы сделать fetch и вывести на страницу текст поста, соответствующего этому заголовку.

В библиотеке есть метод onCycleTo - переход к следующему слайду. Я попробовал получать последний активный слайд с помощью setTimout:

thumbCarouselOptions.onCycleTo = function(data) {
    ....
    setTimeout(() => carousel.querySelector(".active"), 350);
  };

Работает, но всё равно, пока он крутится, несколько слайдов становятся активными, следовательно будет несколько fetch, из которых нужен и актуален будет только последний. Как отмести весь этот “мусор”, чтобы делался только 1 запрос к БД с последним .active?

Я бы сделал запрос “отменяемым”. На каждый новый запрос отменял бы предыдущий.

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

1 лайк

Ооо, какая шикарная вещь!

1 лайк

Сам бот - моя поделка. Ты можешь подписаться на продвинутую версию и получить доступ к модели версии 4 (бесплатный доступ только к версии 3.5, и она заметно похуже для программирования чем четверка).

Тем самым и меня поддержишь меня и получишь годный инструмент.

1 лайк

Дима, а как ты смотришь на такую идею: запихнуть в массив id всех слайдов, которые прошли через центр, получится что-то типа:

['1', '3', '3', '5', '4', '4', '4', '4', '4', '4', '3', '3', '3', '4', '5', '6', '8', '7', '7', '7', '7', '7', '7', '6', '6', '6', '5', '8', '9', '9', '9']

а потом делать fetch по последнему id - в данном случае ‘9’?

И с таймаутом запрашивать последний? Это вариант. Мысленно не вижу возможных проблем с подобным (что не гарантирует невылезание нюансов после реализации).

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

При этом нужно оставаться прагматичным. Если подобный подход решит задачу с минимум затрат усилий, то его вполе можно применить.

1 лайк

Да, в этом-то вся и проблема: все нюансы (как правило, гадостные) вылазят уже после реализации и не всегда их можно спрогнозировать.

Именно так происходит и будет происходить.

Это та часть программирования где средний (потому что бывают люди умеющие продумывать последствия прямо в голове, их мы не берем) человек занимается искусством предвидиния и оценки рисков на этапе проектирования.

Этот вопрос был связан с вопросом про остановку воспроизведения видео при переходе к следующему слайду. Мне кажется, будет проще оставить 1 слайдер - с заголовками, получать активный и по нему делать fetch к тексту поста, чем ловить все видео, инициализировать их через new Player и т.д. Тем более, что визуально ничего не изменится: в имеющемся варианте показывается лишь 1 один слайд с описанием мелодии и визуальный эффект прокрутки не значим

После остановки слайда надо будет продолжить проигрывание при возврате к этому слайду? Если не надо, тогда описанный подход сработает. Оценить его сложность или хрупкость я не могу, потому что оценка зависит от существующего кода.

Возможные проблемы в том когда именно апи карусели даст доступ к содержимому слайда. Если это будет после завершения анимации, то польователь увидит мигание содержмого ифрейма.

Субъективно, при наличии ресурсов (времени, свободы выбора) я бы стремился к тому чтобы состояние видео на каждом слайде сохранялось между прокрутками слайдов потому что это более ожидаемо, как мне кажется, с перспективы пользователя.

На этом месте снова тот же пассаж про прагматизм.

1 лайк

Мне вот тоже думается, что запоминать момент остановки видео на предыдущем слайде более желанно… Ладно, придётся экспериментировать с new Player… Спасибо за обстоятельные ответы!

Всегда пожалуйста. Удачи.

1 лайк

Привет! Я снова “со своими баранами” ) Долго сегодня развлекался с AbortController - не получалось всё же отсечь запросы, кроме последнего. Случайно наткнулся ещё на одну штуку, о которой даже не подозревал - Mutation Observer API. Пришлось углубиться и… Именно он решил мне эту проблему со слайдером:

const observer = new MutationObserver(onSlideClassChange);

function onSlideClassChange(mutationsList) {
  const number = [];
  const target = mutationsList[0].target;
  const isCarouselStopped = !target.classList.contains("scrolling");

  if (isCarouselStopped) {
      number.push(target.querySelector(".carousel-item.active").dataset.number);
      const id = number.pop();

      fetch("https://jsonplaceholder.typicode.com/photos").then(response => response.json()).then(data => console.log(data));
  }
} 

  observer.observe(thumbCarousel, { attributes: true });

Я заметил, что в карусели, пока крутятся слайды с заголовками постов, к контейнеру карусели крепится класс scrolling, установил наблюдение за этим классом. Когда он исчезает, это и есть момент остановки слайдера. Тогда внутри контейнера ищется активный слайд и снимаются его параметры для fetch тела соответствующего поста. Единственное, что осталось для меня загадкой, почему Mutation Observer срабатывает дважды с одним и тем же значением, поэтому я записываю их в массив number, из которого потом беру последний элемент - это и есть нужный мне id. Fetch в коде выше никак с ним не связан - этот кусок кода для теста исключительно.

Пробовал сейчас крутить быстро, медленно - выдаёт только 1 значение и с ним делает fetch. Пока карусель крутится - не срабатывает. Никакие таймеры не нужны, код не зависит от вида события - клики, свайпы по карусели и т.д. Похоже, я нашёл то, что искал. Урррааа!!! )))

1 лайк

Здорово. Рад что получилось разобраться. И решение концептуально проще чем отмена таймеров-запросов. Мне оно нравится больше чем то что я предлагал именно за счет прямолинейности и простоты.

1 лайк

В любом случае, спасибо за идеи и поддержку - вижу, как мои горизонты потихоньку расширяются полезными штуками :) Я честно хотел сделать с AbortController, но вот всё равно он не отсекал все запросы. (

1 лайк