jQuery - własny plugin
Korzystając z jQuery, nie raz używamy różnego rodzajów pluginów, czyli rozszerzeń do tej wspaniałej biblioteki. W tym artykule stworzymy nasze własne rozszerzenie.
Rozszerzenia do jQuery można podzielić na dwie części. Jedne z nich rozszerzają jQuery nie operując na elementach HTML:
$.fn.random = function(min, max) {
return Math.floor(Math.random()*(max-min+1)+min);;
}
console.log($.random(5, 50));
Drugie - bardziej nas interesujące operują na zbiorach elementów. Przykładem takiej funkcji może myć np. fadeOut(), który powoduje zanikanie obiektów, które zostały do niego przekazane.
$(".someElements").fadeOut("slow");
HTML i CSS
Nasz plugin będzie bardzo prostą karuzelą. Zanim zaczniemy pisać kod, stwórzmy HTML i CSS, który nam się przyda.
Pokaż HTMLPokaż CSS
Ogólny schemat pluginów
Ogólny schemat plugiu może mieć postać:
(function($){
$.fn.functionName = function(config) {
const options = $.extend({
//...parametry
}, config);
return this.each(function() {
//...metody, właściwości itp
});
}
})(jQuery);
Nasz plugin powinien mieć określone parametry swojego działania, które użytkownik powinien móc nadpisać własnymi wartościami. W czystym Javascript użylibyśmy tutaj Object.assign() lub stread syntax. Podobne czynności robiliśmy już w rozdziale gdzie tworzyliśmy slider. W jQuery możemy skorzystać z funkcji extend()
:
(function($){
$.fn.carousel = function(config) {
const options = $.extend({
displayElements : 3, //ile elementów będziemy pokazywać
animationTime : 700, //czas animacji
pauseTime : 3000, //przerwa między automatycznym przewijaniem
onScroll : function() {} //opcjonalna funkcja zwrotna po przewinięciu jednego slajdu
}, config);
}
})(jQuery);
Dzięki temu użytkownik używający naszego dodatku będzie mógł go odpalać przekazujac do niego stosowne parametry:
$(".some-div").carousel({
animationTime : 2000
});
Tworzymy kod pluginu
Przechodzimy do meritum. Plugin może być odpalony na pojedynczego ale i dla wielu elementów na stronie. Powinniśmy więc zrobić po nich pętlę i obsłużyć każdy z osobna:
(function($){
$.fn.functionName = function(config) {
const options = $.extend({
//...parametry
}, config);
return this.each(function() {
//...metody, właściwości itp
const $this = $(this);
});
}
})(jQuery);
Po pierwsze podstawmy odpowiednie elementy pod zmienne:
return this.each(function() {
const $this = $(this);
const $ul = $this.find(".carousel-list");
const $li = $ul.find(".carousel-list-el");
const $prevBtn = $this.find(".prev");
const $nextBtn = $this.find(".next");
const itemWidth = $li.first().outerWidth(true); //szerokość elementu - o tyle będzie przesuwał się slider
let time = null; //posłuży do automatycznego przewijania slidera
});
Podepnijmy teraz odpowiednie zdarzenia pod przyciski przesuwające (prev i next):
$prevBtn.on("click", scrollPrev);
$nextBtn.on("click", scrollNext);
Pozostało nam już tylko napisać te zdarzenia.
Pierwsze to scrollPrev()
, które będzie pokazywało wcześniejsze pozycje elementy LI.
W tym momencie przyda się kawałek kartki.
Nasza karuzela będzie miała bardzo prostą zasadę. Jeżeli przewijamy listę w lewo, wtedy na pierwszą pozycję wrzucamy element z jej końca.
Jeżeli listę przesuwamy w prawo, wtedy wrzucimy na jej koniec element z jej początku.
Przy przesuwaniu listy w lewo wykonamy następujące czynności:
- Przesuniemy listę o 1 pole w lewo (
0 - item_width
) - Wstawimy ostatni element listy na jej początek
- Zaanimujemy przesunięcie listy z pozycji
0 - item_width do pozycji 0
Aby zrealizować powyższe kroki musimy utworzyć lokalną metodę, która będzie przesuwać nasz scroller.
const scrollPrev = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.css("margin-left", -item_width);
$li.first().before($li.last());
$ul.animate({"margin-left" : 0}, options.animationTime, function() {
options.onScroll();
});
}
}
Nasze przesuwanie realizujemy tylko w momencie gdy nasza lista się nie przesuwa, stąd na początku sprawdzenie $ul.not(":animated").
Na początku tej metody po raz kolejny pobieram wszystkie LI naszej listy. Czemu?
Pobrane na początku pluginu LI podstawione są już pod zmienną, dlatego nie odzwierciedlają przerzucania z końca na początek i początku na koniec (bo w jQuery gdy pobieramy elementy, podobnie do querySelectorAll nie pobieramy ich jako żywe kolekcje).
Pozostał nam przeciwny kierunek:
- Przesuwamy naszą listę w lewo (0-item_width)
- Po animacji wstawiamy po końcowym LI ten z początku
- ustawiamy pozycję UL na 0
const scrollNext = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.animate({"margin-left" : -itemWidth}, options.animationTime, function() {
$li.last().after($li.first());
$ul.css({"margin-left" : 0});
options.onScroll();
});
}
}
Nasz plugin ma teraz postać:
(function($){
$.fn.carousel = function(config) {
const options = $.extend({
displayLi : 3,
animationTime : 700,
pauseTime : 3000,
onScroll : function() {}
}, config);
return this.each(function() {
const $this = $(this);
const $ul = $this.find(".carousel-list");
const $li = $ul.find(".carousel-list-el");
const item_width = $li.first().outerWidth(true);
const $prevBtn = $this.find(".carousel-prev");
const $nextBtn = $this.find(".carousel-next");
let time = null;
const scrollPrev = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.css("margin-left",-item_width);
$li.first().before($li.last());
$ul.animate({"margin-left" : 0}, options.animationTime, function(){
options.onScroll();
});
}
};
const scrollNext = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.animate({"margin-left" : -item_width}, options.animationTime, function(){
$li.last().after($li.first());
$ul.css({"margin-left" : 0});
options.onScroll();
});
}
};
$prevBtn.bind("click", scrollPrev);
$nextBtn.bind("click", scrollNext);
});
}
})(jQuery);
Automatyczne przewijanie
Aby nasz slider dodatkowo automatycznie się przesuwał, wykorzystamy dobrze nam znaną metodę setTimeout(), którą podstawimy
pod zmienną time
.
Dodajemy więc dodatkową opcję auto
, która automatycznie będzie odpalać funkcję scrollNext():
(function($){
$.fn.carousel = function(config) {
const options = $.extend({
displayLi : 3,
animationTime : 700,
pauseTime : 3000,
onScroll : function() {},
auto : false
}, config);
...
}
Automatyczne przesuwanie powinniśmy odpalić w trzech momentach. Po pierwsze przy starcie naszego plugina (jeżeli użytkownik ustawił opcję auto na true). Po drugie i trzecie - jeżeli użytkownik przestanie klikać na przyciski Poprzedni/Następny.
Żeby nie duplikować kodu, napiszmy dodatkową funkcję i odpalmy ją w stosownych momentach:
(function($){
$.fn.carousel = function(config) {
const options = $.extend({
displayLi : 3,
animationTime : 700,
pauseTime : 3000,
onScroll : function() {},
auto : false
}, config);
return this.each(function() {
const $this = $(this);
const $ul = $this.find(".carousel-list");
const $li = $ul.find(".carousel-list-el");
const item_width = $li.first().outerWidth(true);
const $prevBtn = $this.find(".carousel-prev");
const $nextBtn = $this.find(".carousel-next");
let time = null;
const autoNext = function() {
if (options.auto) {
clearTimeout(time);
time = setTimeout(function() {
scrollNext()
}, options.pauseTime);
}
};
const scrollPrev = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.css("margin-left",-item_width);
$li.first().before($li.last());
$ul.animate({"margin-left" : 0}, options.animationTime, function(){
options.onScroll();
});
autoNext();
}
};
const scrollNext = function() {
if (!$ul.is(":animated")) {
const $li = $ul.find(".carousel-list-el");
$ul.animate({"margin-left" : -item_width}, options.animationTime, function(){
$li.last().after($li.first());
$ul.css({"margin-left" : 0});
options.onScroll();
autoNext();
});
}
};
$prevBtn.bind("click", scrollPrev);
$nextBtn.bind("click", scrollNext);
autoNext();
});
}
})(jQuery);
Przykład użycia
I w zasadzie zakończyliśmy naszą pracę. Pozostaje odpalenie jej dla danych elementów:
$(function() {
$("#demo2").carousel({
displayLi: 3,
animationTime: 300,
pauseTime: 3000,
auto: true
});
});
- ..1..
- ..2..
- ..3..
- ..4..
$(function() {
$("#demo2").carousel({
displayLi: 3,
animationTime: 700,
pauseTime: 500,
auto: false
});
});
- ..1..
- ..2..
- ..3..
- ..4..
Podsumowanie
Powyższy artykuł pokazał ci jak możesz zbudować własny plugin.
Czy budowanie karuzel jest najlepszym wyborem? W dzisiejszych czasach rzucanie się na takie zabawy wydaje się sztuką dla sztuki, ponieważ mamy na rynku świetne rozwiązania takie jak:
- https://kenwheeler.github.io/slick/
- https://owlcarousel2.github.io/OwlCarousel2/
- https://swiperjs.com/
A pamiętajmy, że w naszym - nie ma co ukrywać - prymitywnym rozwiązaniu nie obsłużyliśmy ani responsywności, ani obsługi chociażby palca.