✨ Implement day navigation gestures with Swiper.js
This commit is contained in:
112
src/components/day-carousel.vue
Normal file
112
src/components/day-carousel.vue
Normal file
@ -0,0 +1,112 @@
|
||||
<script setup>
|
||||
import { selectedDate, changeDate, changeDay } from "../store";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
defineProps({
|
||||
element: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Get swiper element
|
||||
const swiperModules = ref([Virtual]);
|
||||
const swiperElement = ref();
|
||||
function setSwiper(swiper) {
|
||||
swiperElement.value = swiper;
|
||||
}
|
||||
|
||||
// Load current, previous and next day
|
||||
const loadedDates = ref([
|
||||
new Date(selectedDate.value.getTime() - 86400000),
|
||||
new Date(selectedDate.value.getTime()),
|
||||
new Date(selectedDate.value.getTime() + 86400000),
|
||||
]);
|
||||
|
||||
// Load left or right date on slide change
|
||||
function slideChange(swiper) {
|
||||
selectedDate.value = loadedDates.value[swiper.activeIndex];
|
||||
const activeSlide = swiper.activeIndex;
|
||||
if (activeSlide == loadedDates.value.length - 1) {
|
||||
const lastDate = loadedDates.value[loadedDates.value.length - 1];
|
||||
loadedDates.value.push(calculateDate(lastDate, 1));
|
||||
}
|
||||
}
|
||||
function slideChangeEnd(swiper) {
|
||||
const activeSlide = swiper.activeIndex;
|
||||
if (activeSlide == 0) {
|
||||
const lastDate = loadedDates.value[0];
|
||||
loadedDates.value = [calculateDate(lastDate, -1), ...loadedDates.value];
|
||||
swiper.slideTo(activeSlide + 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function calculateDate(date, offset) {
|
||||
return new Date(date.getTime() + 86400000 * offset);
|
||||
}
|
||||
function calculateSlide(date) {
|
||||
return loadedDates.value.findIndex((e) => e.getTime() == date.getTime());
|
||||
}
|
||||
function slideToDate(date) {
|
||||
const slide = calculateSlide(date);
|
||||
if (slide != -1) swiperElement.value.slideTo(slide);
|
||||
else {
|
||||
loadedDates.value = [calculateDate(date, -1), date, calculateDate(date, 1)];
|
||||
swiperElement.value.slideTo(1, 0);
|
||||
}
|
||||
selectedDate.value = date;
|
||||
}
|
||||
|
||||
// Watch for slide change instructions
|
||||
watch(changeDay, (change) => {
|
||||
if (change == 0) return;
|
||||
slideToDate(calculateDate(selectedDate.value, change));
|
||||
changeDay.value = 0;
|
||||
});
|
||||
watch(changeDate, (date) => {
|
||||
slideToDate(new Date(date.setUTCHours(0, 0, 0, 0)));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<swiper
|
||||
:modules="swiperModules"
|
||||
:slides-per-view="1"
|
||||
:space-between="50"
|
||||
:initial-slide="1"
|
||||
:virtual="true"
|
||||
@slide-change-transition-end="slideChangeEnd"
|
||||
@slide-change="slideChange"
|
||||
@swiper="setSwiper"
|
||||
>
|
||||
<swiper-slide
|
||||
v-for="(date, index) in loadedDates"
|
||||
:key="index"
|
||||
:virtualIndex="index"
|
||||
>
|
||||
<div class="content">
|
||||
<component :is="element" :date="date" />
|
||||
</div>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import "swiper/css";
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.swiper {
|
||||
padding: 10px;
|
||||
z-index: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: calc(100% - 100px);
|
||||
overflow-y: auto;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user