# ZeenStreamProgramTable
Компонет слайдер
# Примеры:
Default
Расписание
:speeches="speech"
:arrows="false"
:scrollToOnline="false"
Другой текст
# props
Название | Тип | Обязательный | По умолчанию | Описание |
---|---|---|---|---|
speech | Array | - true | - | Массив из компонетов карточек (как заполнять карточки смотрите в компоненте ZeenStreamProgramItem) |
arrows | Boolean | - | true | Показывать стрелки |
scrollToOnline | Boolean | - | true | Автоскролл до онлайна |
settingsSwiper | Object | - | см.ниже | Объект конфигурации swiper |
const defaultSettingSwiper = { breakpoints: { 1336: { slidesPerView: 2.2, spaceBetween: 20, }, 1024: { slidesPerView: 2, spaceBetween: 20, }, 768: { slidesPerView: 1.5, spaceBetween: 20, }, 320: { slidesPerView: 1.08, spaceBetween: 10, }, }, }
# Source Code - исходный код компонента
<template lang="pug">
.stream-table
ZeenContainer
.stream-table__header
slot(name="title")
.stream-table__arrows(v-if="arrows")
ZeenActionIcon(size="big" ref="btnPrev")
slot(name="arrowPrev")
svg.stream-table__arrow(
width="27"
height="24"
viewBox="0 0 27 24"
xmlns="http://www.w3.org/2000/svg"
)
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M27 12C27 11.4477 26.5523 11 26 11H1C0.447716 11 0 11.4477 \
0 12C0 12.5523 0.447716 13 1 13H26C26.5523 13 27 12.5523 27 12Z"
)
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.2628 0.324281C12.8897 0.7314 12.9172 1.36397 13.3243 \
1.73716L24.5201 12L13.3243 22.2629C12.9172 22.636 12.8897 23.2686 \
13.2628 23.6757C13.636 24.0828 14.2686 24.1104 14.6757 23.7372L26.6757 \
12.7372C26.8824 12.5477 27 12.2803 27 12C27 11.7197 26.8824 11.4523 \
26.6757 11.2629L14.6757 0.262852C14.2686 -0.110341 13.636 -0.0828378 \
13.2628 0.324281Z"
)
ZeenActionIcon(size="big" ref="btnNext")
slot(name="arrowNext")
svg(width="27" height="24" viewBox="0 0 27 24" xmlns="http://www.w3.org/2000/svg")
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M27 12C27 11.4477 26.5523 11 26 11H1C0.447716 11 0 11.4477 0 12C0 \
12.5523 0.447716 13 1 13H26C26.5523 13 27 12.5523 27 12Z"
)
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M13.2628 0.324281C12.8897 0.7314 12.9172 1.36397 13.3243 1.73716L24.5201 \
12L13.3243 22.2629C12.9172 22.636 12.8897 23.2686 13.2628 23.6757C13.636 \
24.0828 14.2686 24.1104 14.6757 23.7372L26.6757 12.7372C26.8824 12.5477 27 \
12.2803 27 12C27 11.7197 26.8824 11.4523 26.6757 11.2629L14.6757 0.262852C14.2686 \
-0.110341 13.636 -0.0828378 13.2628 0.324281Z"
)
.stream-table__wrapper.swiper-container(ref="slider")
.swiper-wrapper
.swiper-slide(
v-for="(speech, i) in speeches"
:key="speech.id"
)
ZeenStreamProgramItem(
:key="i"
:speech="speech"
:modalName="`${modalPrefix}speech-speakers-${speech.id}`"
@open-modal="openModal"
v-on="speechEvents"
)
template(v-for="(slot, slotName) in speechSlots" v-slot:[slotName]="params")
slot(:name="`${speechPrefix}${slotName}`" v-bind="params" )
template(v-for="(speech, i) in speeches")
ZeenModal(:name="`${modalPrefix}speech-speakers-${speech.id}`" :key="i")
p.stream-item__modal-title {{ speakerTitle }}
ZeenSpeakerItem.stream-item__speaker.stream-item__speaker_modal(
v-for="(speaker, idx) in speech.speakers"
:speaker="speaker"
:key="idx"
)
</template>
<script>
import Swiper from 'swiper/bundle'
import ZeenContainer from '../ZeenContainer/ZeenContainer'
import ZeenStreamProgramItem from '../ZeenStreamProgramItem/ZeenStreamProgramItem'
import ZeenActionIcon from '../ZeenActionIcon/ZeenActionIcon'
import ZeenModal from '../ZeenModal/ZeenModal'
import ZeenSpeakerItem from '../ZeenSpeakerItem/ZeenSpeakerItem'
import {createSlotsFor} from '../../helpers/createBlockData'
const defaultSettingSwiper = {
breakpoints: {
1336: {
slidesPerView: 2.2,
spaceBetween: 20,
},
1024: {
slidesPerView: 2,
spaceBetween: 20,
},
768: {
slidesPerView: 1.5,
spaceBetween: 20,
},
320: {
slidesPerView: 1.08,
spaceBetween: 10,
},
},
}
export default {
name: 'ZeenStreamProgramTable',
components: {
ZeenSpeakerItem,
ZeenModal,
ZeenContainer,
ZeenStreamProgramItem,
ZeenActionIcon,
},
props: {
speeches: {
type: Array,
require: true,
},
settingsSwiper: {
type: Object,
require: false,
default: () => JSON.parse(JSON.stringify(defaultSettingSwiper)),
},
arrows: {
type: Boolean,
default: true,
},
scrollToOnline: {
type: Boolean,
default: true,
},
modalPrefix: String,
speakerTitle: {
type: String,
default: 'Спикеры трансляции',
},
},
mounted() {
this.initSlider()
},
destroyed() {
this.slider?.destroy(true, true)
},
methods: {
initSlider() {
const config = Object.assign({}, defaultSettingSwiper, this.settingsSwiper)
if (this.arrows) {
config.navigation = {
prevEl: this.$refs.btnPrev.$el,
nextEl: this.$refs.btnNext.$el,
}
}
this.slider = new Swiper(this.$refs.slider, config)
this.updateSlider()
if (this.scrollToOnline) {
this.autoScroll()
}
},
autoScroll() {
let online = 0
this.speeches.some((item, index) => {
if (item.status === 'online') {
online = index
return true
}
})
this.slider.slideTo(online, 250, false)
},
async updateSlider() {
if (!this.slider) {
return
}
await this.$nextTick()
this.slider.update()
},
openModal(modalName) {
this.$vfm.show(modalName)
},
},
computed: {
speechPrefix() {
return 'speech_'
},
speechEvents() {
const prefix = this.speechPrefix
const events = this.$listeners
const entryEventNames = Object.keys(events)
.filter((key) => key.substring(0, prefix.length) === prefix)
.map((key) => key.substring(prefix.length))
return entryEventNames.reduce((acc, entryKey) => {
acc[entryKey] = events[`${prefix}${entryKey}`]
return acc
}, {})
},
speechSlots() {
return createSlotsFor(this, this.speechPrefix)
},
},
watch: {
speeches() {
setTimeout(() => {
this.updateSlider()
}, 1000)
},
},
}
</script>
<style>
:root {
/* Размеры */
--stream-table-arrow-width: 80px;
--stream-table-dot-width: 10px;
--stream-table-swiper-margin-top: 30px;
--stream-program-item-title-mobile-font-size: var(--main-larger-size);
--stream-program-item-title-mobile-font-weight: 600;
--stream-program-modal-speaker-margin-top: 30px;
/* Цвета */
--stream-table-dot-background: var(--gray-2);
--stream-table-dot-background-active: var(--main-color);
}
</style>
<style lang="scss" scoped>
@import './src/styles/mixins.scss';
.stream-table {
width: 100%;
&__header {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
&__arrows {
width: var(--stream-table-arrow-width);
display: flex;
justify-content: space-between;
}
&__arrow {
transform: rotateY(180deg);
}
&__wrapper {
margin-top: var(--stream-table-swiper-margin-top);
}
::v-deep {
.swiper-slide {
height: auto;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
}
}
.stream-item {
&__modal-title {
font-weight: var(--stream-program-item-title-mobile-font-weight);
font-size: var(--stream-program-item-title-mobile-font-size);
line-height: 1.3;
margin: 0 0;
}
&__speaker {
margin-top: var(--stream-program-modal-speaker-margin-top);
width: 100%;
&_modal {
max-width: none;
}
}
}
</style>