Легковесная библиотека для создания нативных слайдеров на чистом JavaScript/TypeScript без зависимостей.
- 🚀 Нативный скролл - использует встроенные возможности браузера
- 📱 Адаптивный - работает на всех устройствах
- ⌨️ Управление клавиатурой - навигация стрелками
- 🎯 IntersectionObserver - отслеживание активного слайда
- 🔄 Loop режим - бесконечная прокрутка
- 📍 Пагинация - автоматически генерируется
- 🎨 Кастомизация - полный контроль над стилями
- 💪 TypeScript - полная типизация
npm install native-slider
# или
yarn add native-slider
# или
pnpm add native-slider<div class="slider-container">
<div class="slider">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
<button class="btn-prev">Previous</button>
<button class="btn-next">Next</button>
<div class="pagination"></div>
</div>import NativeSlider from 'native-slider';
const slider = new NativeSlider({
container: '.slider-container',
slidesSelector: '.slider',
slideSelector: '.slide',
prevButton: '.btn-prev',
nextButton: '.btn-next',
pagination: '.pagination',
loop: true,
keyboard: true
});| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
container |
string | HTMLElement |
обязательно | Контейнер слайдера |
slidesSelector |
string |
'.slider' |
Селектор обёртки слайдов |
slideSelector |
string |
'.slide' |
Селектор отдельного слайда |
prevButton |
string | HTMLElement |
null |
Кнопка "Назад" |
nextButton |
string | HTMLElement |
null |
Кнопка "Вперёд" |
pagination |
string | HTMLElement |
null |
Контейнер пагинации |
initialSlide |
number |
0 |
Начальный слайд |
loop |
boolean |
true |
Зацикливание |
keyboard |
boolean |
true |
Управление клавиатурой |
threshold |
number |
0.5 |
Порог IntersectionObserver |
scrollBehavior |
'smooth' | 'auto' |
'smooth' |
Поведение скролла |
onSlideChange |
(index: number) => void |
() => {} |
Callback при смене слайда |
onInit |
(slider: NativeSlider) => void |
() => {} |
Callback при инициализации |
Переход на конкретный слайд.
slider.goToSlide(2); // С анимацией
slider.goToSlide(2, false); // Без анимацииПереход на следующий слайд.
slider.next();Переход на предыдущий слайд.
slider.prev();Получить индекс текущего слайда.
const currentIndex = slider.getCurrentIndex();
console.log(currentIndex); // 0, 1, 2...Получить общее количество слайдов.
const total = slider.getSlidesCount();
console.log(total); // 5Обновить слайдер (пересчитать слайды, пагинацию).
// После динамического добавления/удаления слайдов
slider.update();Уничтожить экземпляр слайдера.
slider.destroy();<template>
<div class="slider-wrapper">
<div class="slider" ref="sliderContainer">
<div class="slide" v-for="(item, index) in items" :key="index">
{{ item }}
</div>
</div>
<button ref="prevBtn">Prev</button>
<button ref="nextBtn">Next</button>
<div ref="paginationEl"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import NativeSlider from 'native-slider';
const sliderContainer = ref(null);
const prevBtn = ref(null);
const nextBtn = ref(null);
const paginationEl = ref(null);
const items = ref(['Slide 1', 'Slide 2', 'Slide 3']);
let slider = null;
onMounted(() => {
slider = new NativeSlider({
container: sliderContainer.value,
slidesSelector: '.slider',
slideSelector: '.slide',
prevButton: prevBtn.value,
nextButton: nextBtn.value,
pagination: paginationEl.value,
onSlideChange: (index) => {
console.log('Current slide:', index);
}
});
});
onBeforeUnmount(() => {
slider?.destroy();
});
</script>import { useEffect, useRef } from 'react';
import NativeSlider from 'native-slider';
function Slider() {
const sliderRef = useRef(null);
const prevRef = useRef(null);
const nextRef = useRef(null);
const paginationRef = useRef(null);
const sliderInstance = useRef(null);
useEffect(() => {
sliderInstance.current = new NativeSlider({
container: sliderRef.current,
slidesSelector: '.slider',
slideSelector: '.slide',
prevButton: prevRef.current,
nextButton: nextRef.current,
pagination: paginationRef.current,
});
return () => {
sliderInstance.current?.destroy();
};
}, []);
return (
<div className="slider-wrapper">
<div className="slider" ref={sliderRef}>
<div className="slide">Slide 1</div>
<div className="slide">Slide 2</div>
<div className="slide">Slide 3</div>
</div>
<button ref={prevRef}>Previous</button>
<button ref={nextRef}>Next</button>
<div ref={paginationRef}></div>
</div>
);
}Базовые стили для слайдера:
.slider {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
gap: 1rem;
}
.slider::-webkit-scrollbar {
display: none;
}
.slide {
scroll-snap-align: center;
scroll-snap-stop: always;
flex-shrink: 0;
width: 100%;
opacity: 0.5;
transition: opacity 0.3s, transform 0.3s;
}
.slide.active {
opacity: 1;
transform: scale(1);
}
/* Стили пагинации */
.slider-pagination-bullet {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
border: none;
cursor: pointer;
transition: all 0.3s;
}
.slider-pagination-bullet.active {
background: white;
width: 30px;
border-radius: 5px;
}const imageSlider = new NativeSlider({
container: '.image-slider',
prevButton: '.image-prev',
nextButton: '.image-next',
pagination: '.image-pagination',
loop: true,
onSlideChange: (index) => {
console.log(`Showing image ${index + 1}`);
}
});.vertical-slider {
flex-direction: column;
overflow-y: auto;
scroll-snap-type: y mandatory;
height: 100vh;
}
.vertical-slide {
scroll-snap-align: start;
height: 100vh;
}const slider = new NativeSlider({
container: '.auto-slider',
loop: true
});
// Автоплей каждые 3 секунды
const autoplay = setInterval(() => {
slider.next();
}, 3000);
// Остановить при взаимодействии
document.querySelector('.auto-slider').addEventListener('mouseenter', () => {
clearInterval(autoplay);
});- Chrome/Edge: ✅
- Firefox: ✅
- Safari: ✅
- Opera: ✅
- IE11: ❌ (требуются полифилы для IntersectionObserver)
MIT
Pull requests приветствуются! Для больших изменений сначала откройте issue.
Vladimir Khliupnev - GitHub