I'm struggling with changing swipe direction when I rotate my swiper on 90deg. So in the beginning by default it has horizontal direction. When clicking on slide I'm rotating "swiper-container" making it full screen . So it still has swiping direction from left to right , but I need to change from top to bottom without changing in params direction to vertical .
const topSwiper = new Swiper(this.DOMTopSwiper.current, {
spaceBetween: 0,
observer: true,
observeParents: true,
observeSlideChildren: true,
direction: "vertical",
navigation: {
nextEl: ".top-swiper-button-next",
prevEl: ".top-swiper-button-prev",
},
pagination: {
el: ".zoom-amount-slides",
type: "fraction",
},
})
Destroy previous Swiper and reinitialize Swiper giving the direction value. Here is doc
DEMO
let isVertical = true,
direction = 'vertical';
let swiper = initSwiper(direction);
function initSwiper(direction) {
return new Swiper('.swiper-container', {
spaceBetween: 50,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
direction: direction
});
}
function changeDirection() {
isVertical = !isVertical;
direction = isVertical ? 'vertical' : 'horizontal';
let slideIndex = swiper.activeIndex;
swiper.destroy(true, true);
swiper = initSwiper(direction);
swiper.slideTo(slideIndex,0);
}
html, body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color:#000;
margin: 0;
padding: 0;
}
.swiper-container {
width: 400px;
height: 400px;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
<!-- Link Swiper's CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/css/swiper.min.css">
<!-- Swiper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.6/js/swiper.js"></script>
<button onclick='changeDirection()'>Change Direction</button>
<!-- Swiper -->
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
</div>
For who's searching this in 2022, now is possible to update direction using swiper.changeDirection('vertical'); // or horizontal
complete example here:
https://stackblitz.com/edit/swiper-demo-43-change-direction
Try my solution.
//Tested in Swiper 7.2.0
/**
* Insert to your page
*/
var rotate90Swiper = (function (swiper, optIsRotate90) {
var isRoate90 = !!optIsRotate90
swiper.___touches = {}
swiper.___touches.currentX = swiper.touches.currentX
Object.defineProperty(swiper.touches, 'currentX', {
set: function (v) {
if (!isRoate90) {
swiper.___touches.currentX = v
} else {
swiper.___touches.currentY = v
}
},
get: function () {
return swiper.___touches.currentX
}
})
swiper.___touches.currentY = swiper.touches.currentY
Object.defineProperty(swiper.touches, 'currentY', {
set: function (v) {
if (!isRoate90) {
swiper.___touches.currentY = v
} else {
swiper.___touches.currentX = v
}
},
get: function () {
return swiper.___touches.currentY
}
})
return function (b) {
isRoate90 = b
}
})
/**
* How to use
*/
var setRotate90 = rotate90Swiper(YourSwiperInstance, defaultIsRotate90)
setRotate90(false) // swiper rotate 90deg
setRotate90(true) //normal swiper
Quick edit if you need to rotate at 180 your swiperjs
var rotate180Swiper = (function (swiper, optIsRotate180) {
var isRoate180 = !!optIsRotate180
swiper.___touches = {}
swiper.___touches.currentX = swiper.touches.currentX
Object.defineProperty(swiper.touches, 'currentX', {
set: function (v) {
if (!isRoate180) {
swiper.___touches.currentX = -v
} else {
swiper.___touches.currentX = v
}
},
get: function () {
return swiper.___touches.currentX
}
})
return function (b) {
isRoate180 = b
}
})
Just simply add reverseDirection: true, in the autoplay
autoplay: {
delay: 0,
disableOnInteraction: true,
reverseDirection: true,
},
Related
I have some 10 slides in my page, and it is done using react swiper. So I need the pagination (in my case I have used bullets) to be hidden for the slides 1 and 10. Is there a way to hide those using js in react?
One solution.
Use swiper API:
1/2. Detect specific slides by index:
Detect if this slide index is zero for example (first slide) by realIndex & slideChange event than do something:
swiper.on('paginationUpdate', function () {
let realIndex = this.realIndex;
if(realIndex == 0){
console.log("hello first slide");
}
});
2/2. Destroy/Init pagination by API:
swiper.pagination.init()
swiper.pagination.destroy()
swiper.on('slideChange', function () {
let realIndex = this.realIndex;
if(realIndex == 0){
/* Destroy pagination if slide is 1 */
this.pagination.destroy();
}else{
/* Initialize pagination */
this.pagination.init();
}
});
Demo example
(**In HTML - but use the idea/concept for Swiper React):
const swiper = new Swiper('.swiper', {
// Optional parameters
loop: true,
// If we need pagination
pagination: {
el: '.swiper-pagination',
},
// Navigation arrows
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
on: {
init: function () {
console.log('swiper initialized');
/* hide pagination on load */
this.pagination.destroy();
}
},
});
swiper.on('paginationUpdate', function () {
let realIndex = this.realIndex;
if(realIndex == 0){
/* hide pagination if slide is 1 */
this.pagination.destroy();
}else{
/* else show */
this.pagination.init();
}
});
html,
body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper {
width: 100%;
height: 50%;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: flex;
justify-content: center;
align-items: center;
}
<link
rel="stylesheet"
href="https://unpkg.com/swiper#7/swiper-bundle.min.css"
/>
<!-- Slider main container -->
<div class="swiper">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">Slide 1 - Hide pagination</div>
<div class="swiper-slide">Slide 2 - Show pagination</div>
<div class="swiper-slide">Slide 3 - Show pagination</div>
...
</div>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
<script src="https://unpkg.com/swiper#7/swiper-bundle.min.js"></script>
I want to show a part of the second slide into view. Around 20-30%.
I have set slidesPerView to 2.1 (on mobile devices!) to show part of the next slide.
However, when scrolling through the slides it does not snap to the start of the container which results in parts of slides not within the view when scrolling through the swiper.
I've tried setting the height of the slide at 70% but this gives the same issue. I've also been fiddling with the slidesOffsetAfter parameter but no luck.
Slide show snap to start of the container showing the whole image
Next slide should be partially visible
To see the current state of the project: live dev environment
You can see the issue on desktop in horizontal swiper and on tablet view in the vertical swiper.
CSS
<!-- swiper CSS -->
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">
<style>
#media screen and (max-width: 1079px){
.swiper-section {
justify-content: flex-start;
margin-top: 194px;
}
}
#media screen and (max-width: 1079px){
.main-navigation {
left: 45px;
top: 45px;
}
}
#media screen and (max-width: 1079px){
.sub-navigation {
right: 45px;
top: 45px;
}
}
#media screen and (max-width: 1079px){
.swiper-container {
height: 965px;
}
}
.swiper-slide {
padding-bottom: 45px;
}
#media screen and (max-width: 1079px) {
.swiper-slide {
padding-bottom: 0px;
}
}
.swiper-slide:nth-child(even) {
height: 75%;
width: 45vw !important;
}
.swiper-slide:nth-child(odd) {
height: 100%;
width: 55vw !important;
}
#media screen and (max-width: 1079px) {
.swiper-div {
margin: 0px 45px 0px 45px;
}
}
#media screen and (max-width: 1079px) {
.swiper-slide:nth-child(even) {
height: 100%!important;
width: 100% !important;
}
}
#media screen and (max-width: 1079px) {
.swiper-slide:nth-child(odd) {
height: 100%!important;
width: 100% !important;
}
}
.swiper-slide>img {
object-fit: cover;
width: 100%;
height: 100%;
}
.swiper-button-prev,
.swiper-button-next {
display: none;
}
.swiper-container-horizontal>.swiper-pagination-progressbar {
width: 175px;
margin-left: 65px;
border-radius: 50px;
}
.swiper-pagination-progressbar {
margin-top: 733px;
background: #bababa;
}
.swiper-pagination-progressbar .swiper-pagination-progressbar-fill {
background: #888888;
}
.swiper-container-horizontal>.swiper-pagination-progressbar {
height: 12px;
}
.swiper-container-vertical>.swiper-pagination-progressbar {
display: none;
}
</style>
JS
<!-- swiper JS -->
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<!-- Swiper - Extra Step - add arrows and pagination html markup by code (Append) -->
<script>
var swiperNodes = "";
var pagination = '<div class=swiper-pagination></div>';
var next_prev_buttons = '<div class="swiper-button-prev"></div><div class="swiper-button-next"></div>';
var scrollbar = '<div class="swiper-scrollbar"></div>';
var swiperNodes = swiperNodes.concat(pagination, next_prev_buttons);
/* loop throw all swipers on the page */
$('.swiper-container').each(function( index ) {
$( this ).append(swiperNodes);
});
</script>
<!-- swiper JS Initialize -->
<script>
var mySwiper = new Swiper ('.swiper-container', {
// Optional parameters
slidesPerView: 1,
spaceBetween: 30,
freeMode: false,
loop: true,
centeredSlides: false,
// Enable lazy loading
lazy: true,
mousewheel: {
invert: true,
},
keyboard: {
enabled: true,
onlyInViewport: false,
},
scrollbar: {
el: '.swiper-scrollbar',
draggable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
pagination: {
el: '.swiper-pagination',
type: 'progressbar',
},
keyboard: {
enabled: true,
},
breakpoints: {
0: { /* when window >=0px - webflow mobile landscape/portriat */
slidesPerView: 1,
spaceBetween: 10,
slidesOffsetBefore: 0,
direction: 'vertical',
},
767: { /* when window >= 767px - webflow tablet */
slidesPerView: 2.1,
spaceBetween: 30,
slidesOffsetBefore: 0,
direction: 'vertical',
},
1279: { /* when window >= 988px - webflow desktop */
slidesPerView: 2,
spaceBetween: 20,
slidesOffsetBefore: 0,
}
},
/* uncomment if you want autoplay slider
autoplay: {
delay: 3000,
},
*/
/* uncomment if you want scrollbar
scrollbar: {
el: '.swiper-scrollbar',
hide: true,
},
*/
})
</script>
you can change slidesPerView to float number for example 1.5 and if you set optional parameter to centeredSlides: true,loop: trueyou can see little of both prev and next slider
This one will show a partial view of the next and previous slide. In my case it's a full width carousel so I'm using vw in the CSS, but you can use pixels or %
const swiper = new Swiper( selector, {
slidesPerView: 'auto',
centeredSlides: true,
loop: true,
slidesPerGroup: 1,
paginationClickable: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
} );
And the CSS:
.swiper-slide {
width: 80vw;
}
I've managed to show a part of the next slide only and both creating a div outside the div.swiper-container and style the inner div with padding, which can create the wanted effect.
If you only want to show the preview of the next, style only the padding-right or padding-left and you should be good to go.
The padding applied should consider the spaces between the containers. In my case the spaceBetween was 10, so I used 20px as padding.
Here's some pseudo code:
<script>
const swiper = new Swiper( '.my-class', {
slidesPerView: 2,
spaceBetween: 10,
slidesPerGroup: 2,
centeredSlides: false,
loop: true,
paginationClickable: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
} );
</script>
<style>
.full-width {
margin: 0 calc(-100vw / 2 + 100% / 2) !important;
width: 100vw;
}
.my-class {
padding: 20px;
}
</style>
<div class="full-width">
<div class="swiper-container my-class">
...
</div>
<div>
here is my experience:
i want 5 slide items,
the start item and end item show perfect half size.
$_offset_x: half size of each item, i use percentage according to the design.
.swiper-wrapper {
// left: $_offset_x!important;
left: 9.63%!important;
}
use media query if you have addtional need for mobile.
If you want to show 1 Slide Full and 2nd slide half you can use the config like
slidesPerView: 1.2, Working in swiper version 8.3
I am using swiper.js to create a nested swiper for my website. I am using the renderBullet function to create a custom pagination for it. This works great for the parent swiper and the first nested swiper.
However, when there are more nested swipers, all nested swipers have the pagination of the first nested swiper.
$('.swiper-container-nested').each(function () {
var namesNested = [];
$(".c-home__slide-nested.swiper-slide").each(function () {
namesNested.push($(this).data("name"));
});
var swiperNested = new Swiper('.c-home__swiper-nested.swiper-container-nested', {
speed: 0,
spaceBetween: 100,
direction: 'horizontal',
nested: true,
autoHeight: true,
pagination: {
el: '.swiper-pagination-nested',
clickable: 'true',
type: 'bullets',
renderBullet: function (index, className) {
return '<li class="' + className + ' c-link secondary">' + (namesNested[index]) + '</li>';
},
bulletClass: 'c-menu__item',
bulletActiveClass: 'active',
},
allowTouchMove: false,
a11y: {
prevSlideMessage: 'Previous section',
nextSlideMessage: 'Next section',
firstSlideMessage: 'This is the first section',
lastSlide: 'This is the last section',
paginationBulletMessage: 'Go to section {{index}}'
},
});
});
I know that I somehow need to iterate the following bit for each nested swiper, but I don't know how:
var namesNested = [];
$(".c-home__slide-nested.swiper-slide").each(function () {
namesNested.push($(this).data("name"));
});
Hard to know your problem only by JS (Without HTML markup // complete-example).
No known issue with Swiper Pagination related to custom pagination
Maybe the code-snippet below will be helpful.
Nested each loop
In your code looks like you always loop throw the same element(For the nested-array) - i solve this by using this:
.children() (swiper-wrapper element) ==> .children() (swiper-slide elements)
$this.children().children().each(function(index, element) {
/*do something*/
Related stackoverflow Q:
Targeting $(this) within nested for each loops in jQuery
$.each() with nested array
Nested swipers - Get Custom pagination text from data-attribute (Jquery):
var swiperH = new Swiper(".swiper-container-h", {
spaceBetween: 50,
pagination: {
el: ".swiper-pagination-h",
clickable: true
}
});
// 1. outer loop //
$(".swiper-container-nested").each(function(index, element) {
var $this = $(this);
var fruitsArray = [];
// 1.1. nested loop
$this.children().children().each(function(index, element) {
fruitsArray.push($(this).data("fruit"));
});
/* create swiper objects */
$this.addClass("instance-" + index);
var swiperNested = new Swiper(".instance-" + index, {
direction: "vertical",
spaceBetween: 50,
pagination: {
el: ".swiper-pagination-nested",
clickable: true,
renderBullet: function(index, className) {
return (
'<span class="' +
className +
'">' +
(index + 1) +
"." +
fruitsArray[index] +
"</span>"
);
}
}
});
});
html,
body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper-container {
width: 100%;
height: 100%;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
.swiper-container-v {
background: #eee;
}
.swiper-pagination-nested .swiper-pagination-bullet {
width: auto;
height: 20px;
text-align: center;
border-radius: 5px;
line-height: 20px;
font-size: 12px;
padding: 5px 9px;
color:#000;
opacity: 1;
background: rgba(0,0,0,0.2);
}
.swiper-pagination-nested .swiper-pagination-bullet-active {
color:#fff;
background: red;
}
ul.swiper-wrapper,
li.swiper-slide {
padding: 0px;
margin: 0px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.1/css/swiper.min.css" rel="stylesheet"/>
<!-- Swiper -->
<main class="swiper-container swiper-container-h">
<ul class="swiper-wrapper">
<li class="swiper-slide">
<div class="swiper-container swiper-container-nested">
<div class="swiper-wrapper">
<div data-fruit="Orange" class="swiper-slide">1. Orange</div>
<div data-fruit="Apple" class="swiper-slide">2. Apple</div>
<div data-fruit="Cranberry" class="swiper-slide">3. Cranberry</div>
<div data-fruit="Guava" class="swiper-slide">4. Guava</div>
<div data-fruit="Pumpkin" class="swiper-slide">5. Pumpkin</div>
</div>
<div class="swiper-pagination swiper-pagination-nested"></div>
</div>
</li>
<li class="swiper-slide">
<div class="swiper-container swiper-container-nested">
<div class="swiper-wrapper">
<div data-fruit="Cranberry" class="swiper-slide">1. Cranberry</div>
<div data-fruit="Guava" class="swiper-slide">2. Guava</div>
<div data-fruit="Pumpkin" class="swiper-slide">3. Pumpkin</div>
</div>
<div class="swiper-pagination swiper-pagination-nested"></div>
</div>
</li>
<li class="swiper-slide">
<div class="swiper-container swiper-container-nested">
<div class="swiper-wrapper">
<div data-fruit="Lemon" class="swiper-slide">1. Lemon</div>
<div data-fruit="Melon" class="swiper-slide">2. Melon</div>
</div>
<div class="swiper-pagination swiper-pagination-nested"></div>
</div>
</li>
</ul>
<!-- Add Pagination -->
<div class="swiper-pagination swiper-pagination-h"></div>
</main>
<!-- assets -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.1/js/swiper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src=""></script>
Related: Read this Github issue:
Multiple Instances of Swiper on Same page? #273
Codepen
https://codepen.io/ezra_siton/pen/MWgqMde?editors=1010
I want make a slider with Swiperjs like Apple App Store carousel (you can see at Games tab).
I tried to make it in Vue Swiper (a package for vue) here:
HTML code:
<div id="app">
<h1>Slider</h1>
<!-- Slider main container -->
<vue-swiper url="http://www.google.com"></vue-swiper>
<div>
CSS:
ody {
background: #f0f0f0;
font-family: Tahoma;
}
#app{
width:400px;
height:700px;
background:white;
margin: auto;
border-radius: 10px;
}
h1 {
padding: 30px 10px 0 10px;
}
.swiper-container {
padding-top: 10px;
width: 100%;
height: 180px;
}
.swiper-slide {
width: 300px;
border-radius: 5px;
text-align: center;
color: #fff;
background: url('https://i.vimeocdn.com/video/376634544.jpg?mw=1920&mh=1080&q=70');
background-size: cover;
}
Javascript code:
ue.component('vue-swiper', {
data: function() {
return {
imageItems:[]
};
},
props:['url'],
mounted: function () {
var mySwiper = new Swiper ('.swiper-container', {
slidesPerView: 'auto',
spaceBetween: 10,
centeredSlides:true,
direction: 'horizontal',
loop: false,
// pagination: '.swiper-pagination',
// paginationType:'bullets',
nextButton: false,
prevButton: false,
});
},
template:`
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide"></div>
<div class="swiper-slide"></div>
<div class="swiper-slide"></div>
</div>
// <div class="swiper-pagination"></div>
</div>
`
});
var app = new Vue({
el: '#app',
data: {
},
})
How can I make the first slide float to left and the last slide float to right, like this:
In my code, the first slide and the last slide are centered.
I think I really resolved my issue.
On mounted, when Swiper initiate, I add custom style
on: {
init: function () {
document.getElementById('wrapper').style.transform = "translate3d(10px, 0px, 0px)"
},
}
On touchend (swiper event)
mySwiper.on('touchEnd', function () {
setTimeout(() => {
if (mySwiper.activeIndex == 0) {
document.getElementById('wrapper').style.transform = "translate3d(10px, 0px, 0px)"
}
if (mySwiper.activeIndex == mySwiper.slides.length - 1) {
var translate_last = mySwiper.snapGrid[mySwiper.activeIndex] + mySwiper.snapGrid[0] + 10;
var translate_style = 'translate3d(-' + translate_last + 'px, 0px, 0px)';
document.getElementById('wrapper').style.transform = translate_style
}
}, 10);
});
Check my new Codepen
u fire the event only at the end.
if u slide back it wouldn't transform slides back to initialtion-part.
change it to mySwiper.on('progress', ...
swiper.on('progress', function(){
setTimeout(() => {
if (swiper.activeIndex == 0) {
$(".swiper-slide").css('transform', 'translate3d(125px, 0px, 0px)');
}
if (swiper.activeIndex == swiper.slides.length - 1) {
var translate_last = swiper.snapGrid[swiper.activeIndex] + swiper.snapGrid[0] + 10;
var translate_style = 'translate3d(-' + translate_last + 'px, 0px, 0px)';
$(".swiper-slide").css('transform', translate_style);
}
}, 10);
swiper.on('reachEnd', function(){
$(".swiper-slide").css('transform', 'translate3d(0px, 0px, 0px)');
});
});
I have a vertical slider and I'm using swiper to navigate through the slides.
Every swiper-slide container height is 100vh.
I have a slide which content is greater than the view height and when scrolling with the mousewheel, I want to first scroll it's content and when the end or top is reached, according to the scroll direction, move to the next or previous slide.
I went through swiper documentation, SO and other pages but didn't find a solution.
Here is the jsfiddle:
https://jsfiddle.net/gentian28/6wdsep1v/13/
HTML
<div class="swiper-container">
<main class="main swiper-wrapper">
<!-- landing -->
<section id="home" class="swiper-slide">
<div id="particles-js"></div>
<div id="typeIt" class="d-flex align-center"></div>
</section>
<!-- about -->
<section id="about" class="swiper-slide">
<span class="animation">About</span>
</section>
<!-- portfolio -->
<section id="portfolio" class="swiper-slide d-flex flex-wrap col-3">
<div class="card">
card 1
</div>
<div class="card">
card 2
</div>
<div class="card">
card 3
</div>
<div class="card">
card 4
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
</section>
<!-- technologies -->
<section id="skills" class="swiper-slide">
Skills
</section>
<!-- contact -->
<section id="contact" class="swiper-slide">
Contact
</section>
</main>
</div>
CSS
body {
margin: 0;
padding: 0;
}
.d-flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.flex-column {
flex-flow: column;
}
.column-reverse {
flex-flow: column-reverse;
}
.flex-wrap {
flex-wrap: wrap;
}
.col-2 > * {
width: calc(100% / 2 - 7.5px);
margin-right: 15px;
margin-bottom: 15px;
}
.col-2 > *:nth-child(2n) {
margin-right: 0;
}
.col-3 > * {
width: calc(100% / 3 - 10px);
margin-right: 15px;
}
.col-3 > *:nth-child(3n) {
margin-right: 0;
}
.col-4 > * {
width: calc(100% / 4 - 10.5px);
margin-right: 14px;
}
.col-4 > *:nth-child(4n) {
margin-right: 0;
}
.card {
height: 300px;
}
.swiper-container {
width: 100% - 120px;
height: 100vh;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
overflow-y: auto;
}
.swiper-pagination {
display: flex;
flex-flow: column;
}
.swiper-pagination-bullet-active {
opacity: 0;
}
.swiper-pagination-bullet {
width: 120px;
height: 96px;
border-radius: 0;
opacity: 0;
}
JS
const swiperConf = {
direction: 'vertical',
slidesPerView: 1,
spaceBetween: -1,
mousewheel: true,
keyboard: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
}
}
var swiper = new Swiper('.swiper-container', swiperConf);
ahh guys! thank you a lot for the input, i had the same issue. but your solutions didnt work for me on mobile devices.
so i tried sth own with your input and hacked a little bit.
so here is mine:
(my first post on stack overflow yee)
const handleScrollInside = (swiper) => {
swiper.on("slideChangeTransitionEnd", () => {
const activeSlide = document.querySelector('.swiper-slide-active');
const hasVerticalScrollbar = activeSlide.scrollHeight > activeSlide.clientHeight;
if (hasVerticalScrollbar) {
const scrollDifferenceTop = activeSlide.scrollHeight - activeSlide.swiperSlideSize;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop += 1;
if (activeSlide.scrollTop === scrollDifferenceTop) activeSlide.scrollTop -= 2;
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
activeSlide.addEventListener("scroll", () => {
if (activeSlide.scrollTop <= 0 || scrollDifferenceTop - activeSlide.scrollTop <= 1 ) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
}
});
}
})
}
Also ran into this issue, and the fiddle from #Daryll was very helpful, but with typescript there were some issues getting the 'swiperSlideSize' from an HTMLElement (also using reactjs there are some differences). This worked for me as the event handler for 'onSlideChangeTransitionEnd':
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (scrollUp && activeSlide.scrollTop === 0) {
swiper.mousewheel.enable();
activeSlide.removeEventListener("wheel", findScroll);
} else if (!scrollUp && activeSlide.scrollTop === diff) {
swiper.mousewheel.enable();
activeSlide.scrollTop = 0;
activeSlide.removeEventListener("wheel", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
swiper.mousewheel.disable();
}
};
edit: the "SwiperEvent" type is an alias I'm using with import { Swiper as SwiperEvent } from "swiper"; to avoid namespace conflict with import { Swiper } from "swiper/react";
edit 2: for mobile usage, you have to consider 'touchmove' events, which don't (always?) register the 'wheel' event. By disabling 'allowTouchMove' on the swiper, you achieve the same effect on mobile as with mousewheel.disable() on desktop. Here's some code for that case:
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop = 1;
else if (activeSlide.scrollTop === diff) activeSlide.scrollTop = diff - 1;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (
(scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop <= 0
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
} else if (
(!scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop >= diff
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
activeSlide.addEventListener("touchmove", findScroll);
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
}
};
Basically, by setting the scrollTop to 1px from either the top or bottom of the range, you prevent the mousewheel.enable() call from triggering immediately. In the original version, the slide would always start at the top of the scroll height when activated, while this version starts at the "top" (technically 1px down) if you're swiping down to it and the "bottom" if you're swiping up to it.