Last active
August 17, 2021 22:50
-
-
Save b4n92uid/7d52a2928614f00ea8683ae3087bd90f to your computer and use it in GitHub Desktop.
[Vuetify] Swiper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<!-- Slider main container --> | |
<div | |
class="ok-swiper" | |
:class="{ | |
'--fill-height': fillHeight, | |
'--pagination': pagination, | |
'--navigation': navigation, | |
'--navigation-ex': navigationEx | |
}" | |
> | |
<div v-if="gradient" :style="gradientStyle" class="__gradient"></div> | |
<div v-if="navigationEx" class="__prev"> | |
<v-btn icon @click="prev"><v-icon>mdi-menu-left</v-icon></v-btn> | |
</div> | |
<div class="swiper-container" ref="container"> | |
<div class="swiper-wrapper"> | |
<div | |
class="swiper-slide" | |
:class="{ | |
'swiper-slide-auto': slidesPerView == 'auto', | |
...slideClassObject | |
}" | |
v-for="(item, index) in items" | |
:key="itemValue ? item[itemValue] : index" | |
> | |
<slot :item="item" :index="index"></slot> | |
</div> | |
</div> | |
<div class="swiper-pagination" ref="pagination" v-if="pagination"> | |
<slot name="pagination"></slot> | |
</div> | |
<template v-if="navigation"> | |
<slot name="button-prev"> | |
<div class="swiper-button-prev" ref="buttonPrev"> | |
<v-btn small fab | |
><v-icon large>{{ | |
$vuetify.rtl ? "mdi-menu-right" : "mdi-menu-left" | |
}}</v-icon></v-btn | |
> | |
</div> | |
</slot> | |
<slot name="button-next"> | |
<div class="swiper-button-next" ref="buttonNext"> | |
<v-btn small fab | |
><v-icon large>{{ | |
$vuetify.rtl ? "mdi-menu-left" : "mdi-menu-right" | |
}}</v-icon></v-btn | |
> | |
</div> | |
</slot> | |
</template> | |
<div class="swiper-scrollbar" ref="scrollbar" v-if="scrollbar"> | |
<slot name="scrollbar"></slot> | |
</div> | |
</div> | |
<div v-if="navigationEx" class="__next"> | |
<v-btn icon @click="next"><v-icon>mdi-menu-right</v-icon></v-btn> | |
</div> | |
</div> | |
</template> | |
<script> | |
import { isNumber, merge } from "lodash"; | |
import { classFormatValue } from "@/utils/Array"; | |
import Swiper from "swiper"; | |
import "swiper/dist/css/swiper.min.css"; | |
export default { | |
props: { | |
items: { | |
type: Array, | |
default: () => [] | |
}, | |
itemValue: { | |
type: String, | |
default: null | |
}, | |
autoplay: { | |
type: [Boolean, Number], | |
default: false | |
}, | |
slidesPerView: { | |
type: [Number, String], | |
default: 1.1 | |
}, | |
spaceBetween: { | |
type: Number, | |
default: 16 | |
}, | |
pagination: { | |
type: Boolean, | |
default: false | |
}, | |
navigation: { | |
type: Boolean, | |
default: false | |
}, | |
navigationEx: { | |
type: Boolean, | |
default: false | |
}, | |
scrollbar: { | |
type: Boolean, | |
default: false | |
}, | |
options: { | |
type: Object, | |
default: () => ({}) | |
}, | |
currentSlide: { | |
type: Number, | |
default: 0 | |
}, | |
gradient: { | |
type: Boolean, | |
default: false | |
}, | |
gradientColor: { | |
type: String, | |
default: "white" | |
}, | |
slideClass: { | |
type: [Object, String, Array], | |
default: null | |
}, | |
fillHeight: { | |
type: Boolean, | |
default: false | |
}, | |
disabled: { | |
type: Boolean, | |
default: false | |
} | |
}, | |
data() { | |
return { | |
swiper: null | |
}; | |
}, | |
mounted() { | |
const config = { | |
direction: "horizontal", | |
slidesPerView: this.slidesPerView, | |
spaceBetween: this.spaceBetween, | |
on: { | |
slideChange: () => this.$emit("slideChange", this.swiper.activeIndex) | |
} | |
}; | |
if (this.autoplay !== false) | |
config.autoplay = { | |
delay: isNumber(this.autoplay) ? this.autoplay : 5000 | |
}; | |
if (this.pagination) | |
config.pagination = { | |
el: this.$refs.pagination | |
}; | |
if (this.navigation) | |
config.navigation = { | |
nextEl: this.$refs.buttonNext, | |
prevEl: this.$refs.buttonPrev | |
}; | |
if (this.scrollbar) | |
config.scrollbar = { | |
el: this.$refs.scrollbar | |
}; | |
merge(config, this.options); | |
this.swiper = new Swiper(this.$refs.container, config); | |
if (this.disabled) { | |
this.swiper.detachEvents(); | |
} | |
}, | |
updated() { | |
this.swiper.update(); | |
}, | |
watch: { | |
currentSlide(index) { | |
this.swiper.slideTo(index); | |
}, | |
slidesPerView(v) { | |
this.swiper.params.slidesPerView = v; | |
}, | |
spaceBetween(v) { | |
this.swiper.params.spaceBetween = v; | |
}, | |
disabled() { | |
if (this.disabled) this.swiper.detachEvents(); | |
else this.swiper.attachEvents(); | |
} | |
}, | |
computed: { | |
gradientStyle() { | |
const cssColor = | |
this.gradientColor[0] === "#" | |
? this.gradientColor | |
: `var(--v-${this.gradientColor}-base)`; | |
return { | |
background: `linear-gradient(to left, ${cssColor} 5%, transparent 25%)` | |
}; | |
}, | |
slideClassObject() { | |
return classFormatValue(this.slideClass); | |
} | |
}, | |
methods: { | |
update() { | |
this.swiper.update(); | |
}, | |
prev() { | |
this.swiper.slidePrev(); | |
}, | |
next() { | |
this.swiper.slideNext(); | |
} | |
} | |
}; | |
</script> | |
<style lang="scss"> | |
.ok-swiper { | |
position: relative; | |
.__gradient { | |
content: ""; | |
pointer-events: none; | |
position: absolute; | |
left: -1px; | |
right: -1px; | |
bottom: -1px; | |
top: -1px; | |
z-index: 2; | |
} | |
.swiper-container { | |
.swiper-button-prev { | |
background-image: none; | |
width: auto; | |
height: auto; | |
} | |
.swiper-button-next { | |
background-image: none; | |
width: auto; | |
height: auto; | |
} | |
.swiper-button-next.swiper-button-disabled, | |
.swiper-button-prev.swiper-button-disabled { | |
pointer-events: all; | |
} | |
.swiper-slide.swiper-slide-auto { | |
width: auto; | |
} | |
} | |
} | |
.ok-swiper.--navigation-ex { | |
display: flex; | |
align-items: center; | |
gap: 4px; | |
.swiper-container { | |
flex-grow: 1; | |
} | |
> .__prev { | |
flex-grow: 0; | |
} | |
> .__next { | |
flex-grow: 0; | |
} | |
} | |
.ok-swiper.--fill-height { | |
.swiper-wrapper { | |
align-items: stretch; | |
.swiper-slide { | |
height: auto; | |
} | |
} | |
} | |
.ok-swiper.--pagination { | |
--pagination-height: 48px; | |
.swiper-container { | |
padding-bottom: var(--pagination-height); | |
} | |
.swiper-pagination-bullets { | |
bottom: calc(var(--pagination-height) / 2 - 24px / 2); | |
.swiper-pagination-bullet-active { | |
background: var(--v-primary-base); | |
} | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment