|
|
hai 3 semanas | |
|---|---|---|
| .. | ||
| README.md | hai 3 semanas | |
| index.coffee | hai 3 semanas | |
| index.pug | hai 3 semanas | |
| index.styl | hai 3 semanas | |
ImageSlider - универсальный компонент для создания слайдеров изображений с поддержкой автоматической прокрутки, ручного управления, индикаторов и адаптивного дизайна. Компонент оптимизирован для работы с мультиязычным контентом и поддерживает различные типы медиа-контента.
https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/ImageSlider/
# В основном файле приложения (app/temp.coffee)
components:
'imageslider': require 'app/shared/ImageSlider'
imageslider(:slides="slides")
imageslider(
:slides="featuredSlides"
:autoplay="true"
:interval="5000"
:show-indicators="true"
:show-controls="true"
)
slides (обязательный)ArrayСтруктура слайда:
{
_id: String
type: 'slide'
title: Array[String] # Мультиязычные заголовки
content: Array[String] # Мультиязычный контент
image: Array[String] # Мультиязычные пути к изображениям
slide_data: {
order: Number
active: Boolean
button_text: Array[String]
button_link: Array[String]
button_style: String
text_color: Array[String]
text_position: Array[String]
overlay: Array[Boolean]
overlay_opacity: Array[Number]
}
}
autoplay (опциональный)Booleantrueinterval (опциональный)Number4000showIndicators (опциональный)BooleantrueshowControls (опциональный)Booleantrueheight (опциональный)String'400px'transition (опциональный)String'slide''slide', 'fade'@slide-change{ currentSlide: Object, index: Number }Пример:
imageslider(:slides="slides" @slide-change="onSlideChange")
@slide-click{ slide: Object, index: Number }Пример:
imageslider(:slides="slides" @slide-click="onSlideClick")
[slide] (кастомный контент слайда){ slide: Object, index: Number, active: Boolean }Пример:
imageslider(:slides="slides")
template([slide]="{ slide, index, active }")
div(class="relative h-full flex items-center justify-center")
img(:src="slide.image" :alt="slide.title" class="w-full h-full object-cover")
div(v-if="active" class="absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center")
h2(class="text-white text-4xl font-bold") {{ slide.title }}
[indicators] (кастомные индикаторы){ slides: Array, currentIndex: Number, goToSlide: Function }Пример:
imageslider(:slides="slides")
template([indicators]="{ slides, currentIndex, goToSlide }")
div(class="flex space-x-2 absolute bottom-4 left-1/2 transform -translate-x-1/2")
button(
v-for="(slide, index) in slides"
:key="slide._id"
@click="goToSlide(index)"
:class="currentIndex === index ? 'bg-white' : 'bg-white bg-opacity-50'"
class="w-3 h-3 rounded-full transition-all"
)
[controls] (кастомные кнопки управления){ nextSlide: Function, prevSlide: Function }Пример:
imageslider(:slides="slides")
template([controls]="{ nextSlide, prevSlide }")
div(class="absolute inset-y-0 left-0 flex items-center")
button(@click="prevSlide" class="ml-4 p-2 bg-black bg-opacity-50 text-white rounded-full")
icon(name="chevron-left")
div(class="absolute inset-y-0 right-0 flex items-center")
button(@click="nextSlide" class="mr-4 p-2 bg-black bg-opacity-50 text-white rounded-full")
icon(name="chevron-right")
nextSlide()Пример использования:
imageslider(ref="slider" :slides="slides")
@$refs.slider.nextSlide()
prevSlide()Пример использования:
@$refs.slider.prevSlide()
goToSlide(index)index: NumberПример использования:
@$refs.slider.goToSlide(2) # Переход к третьему слайду
play()Пример использования:
@$refs.slider.play()
pause()Пример использования:
@$refs.slider.pause()
imageslider(
:slides="_.appState.slides"
:autoplay="true"
:interval="5000"
:height="'600px'"
:show-indicators="true"
:show-controls="true"
@slide-change="trackSlideView"
class="rounded-lg shadow-xl"
)
imageslider(
:slides="eventSlides"
:autoplay="false"
:show-indicators="false"
class="event-slider"
)
template([slide]="{ slide, index, active }")
div(class="relative h-80 rounded-lg overflow-hidden shadow-lg")
img(
:src="getText(slide.image)"
:alt="getText(slide.title)"
class="w-full h-full object-cover"
)
div(class="absolute inset-0 bg-gradient-to-t from-black via-transparent to-transparent flex items-end")
div(class="p-6 text-white")
h3(class="text-xl font-bold mb-2") {{ getText(slide.title) }}
p(class="text-gray-200 mb-4") {{ getText(slide.content) }}
app-link(
:to="getText(slide.slide_data.button_link)"
class="inline-block bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
) {{ getText(slide.slide_data.button_text) }}
imageslider(
:slides="productSlides"
:height="'300px'"
:show-controls="false"
:autoplay="true"
:interval="3000"
class="product-slider"
)
template([indicators]="{ slides, currentIndex, goToSlide }")
div(class="flex justify-center space-x-1 mt-4")
button(
v-for="(slide, index) in slides"
:key="slide._id"
@click="goToSlide(index)"
:class="currentIndex === index ? 'w-8 bg-blue-600' : 'w-2 bg-gray-300'"
class="h-2 rounded-full transition-all duration-300"
)
imageslider(
:slides="gallerySlides"
:autoplay="false"
:transition="'fade'"
:height="'100vh'"
class="gallery-slider"
)
template([controls]="{ nextSlide, prevSlide }")
div(class="absolute inset-0 flex items-center justify-between pointer-events-none")
button(
@click="prevSlide"
class="pointer-events-auto ml-8 p-4 bg-black bg-opacity-50 text-white rounded-full hover:bg-opacity-70 transition-opacity"
)
icon(name="arrow-left" class="w-6 h-6")
button(
@click="nextSlide"
class="pointer-events-auto mr-8 p-4 bg-black bg-opacity-50 text-white rounded-full hover:bg-opacity-70 transition-opacity"
)
icon(name="arrow-right" class="w-6 h-6")
imageslider(:slides="slidesWithOverlay")
template([slide]="{ slide, active }")
div(class="relative h-full")
img(
:src="getText(slide.image)"
:alt="getText(slide.title)"
class="w-full h-full object-cover"
)
div(
v-if="slide.slide_data.overlay"
:style="{
backgroundColor: 'rgba(0,0,0,' + (slide.slide_data.overlay_opacity || 0.4) + ')'
}"
class="absolute inset-0 flex items-center justify-center"
)
div(
:class="'text-' + (getText(slide.slide_data.text_position) || 'center')"
:style="{ color: getText(slide.slide_data.text_color) || '#ffffff' }"
class="max-w-2xl px-8"
)
h2(class="text-4xl font-bold mb-4") {{ getText(slide.title) }}
p(class="text-xl mb-6") {{ getText(slide.content) }}
app-link(
v-if="getText(slide.slide_data.button_text)"
:to="getText(slide.slide_data.button_link)"
:class="getButtonStyle(slide.slide_data.button_style)"
class="inline-block px-8 py-3 rounded-lg font-semibold transition-colors"
) {{ getText(slide.slide_data.button_text) }}
imageslider(:slides="multilingualSlides")
template([slide]="{ slide }")
div(class="relative h-full")
img(
:src="AppDB.multilingual.getText(slide.image)"
:alt="AppDB.multilingual.getText(slide.title)"
class="w-full h-full object-cover"
)
div(class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent p-6")
h3(class="text-white text-2xl font-bold mb-2")
| {{ AppDB.multilingual.getText(slide.title) }}
p(class="text-gray-200")
| {{ AppDB.multilingual.getText(slide.content) }}
methods:
onSlideChange: (data) ->
# data: { currentSlide: Object, index: Number }
analytics.track('slide_view', {
slide_id: data.currentSlide._id
slide_index: data.index
slide_title: AppDB.multilingual.getText(data.currentSlide.title)
})
onSlideClick: (data) ->
# data: { slide: Object, index: Number }
if data.slide.slide_data?.button_link
EventBus.emit('slide_button_click', {
slide: data.slide
button_text: AppDB.multilingual.getText(data.slide.slide_data.button_text)
button_link: AppDB.multilingual.getText(data.slide.slide_data.button_link)
})
.image-slider
--slider-height: 400px
--slider-transition-duration: 0.5s
--indicator-size: 12px
--indicator-active-color: #3B82F6
--indicator-inactive-color: #9CA3AF
--control-size: 48px
--control-bg: rgba(0, 0, 0, 0.5)
--control-color: #FFFFFF
// Темная тема
.image-slider--dark
--indicator-active-color: #60A5FA
--indicator-inactive-color: #4B5563
--control-bg: rgba(255, 255, 255, 0.1)
--control-color: #F9FAFB
// Минималистичная тема
.image-slider--minimal
--indicator-size: 8px
--control-size: 40px
--control-bg: transparent
--control-color: #1F2937
.image-slider__control
border: 1px solid #E5E7EB
imageslider(:slides="optimizedSlides")
template([slide]="{ slide }")
div(class="relative h-full")
img(
:src="getOptimizedImage(slide.image)"
:alt="getText(slide.title)"
loading="lazy"
class="w-full h-full object-cover"
)
imageslider(:slides="slides")
template([slide]="{ slide }")
div(class="relative h-full")
img(
:src="getText(slide.image)"
:alt="getText(slide.title)"
@error="handleImageError"
class="w-full h-full object-cover"
)
imageslider(
:slides="slides"
aria-label="Галерея изображений"
role="region"
)
imageslider(
:slides="lazyLoadedSlides"
:autoplay="isVisible"
@slide-change="preloadNextSlide"
)
# В родительском компоненте
mounted: ->
EventBus.on 'slide_change', (data) ->
debug.log "Слайд изменен: "+data.index
EventBus.on 'slider_autoplay_status', (data) ->
debug.log "Автопрокрутка: "+(data.playing ? 'включена' : 'выключена')
computed:
validatedSlides: ->
return @slides.filter (slide) ->
slide.image? and
slide.image.length > 0 and
slide.slide_data?.active isnt false
Компонент ImageSlider предоставляет богатый функционал для создания адаптивных, доступных и производительных слайдеров с полной поддержкой мультиязычности и кастомизации.