SwiperJS not showing next/prev icons but area is clickable - swiper.js

I have pages I am using swiperJS with you can follow an example here:
https://pleinairarchive.com/painting-date/july-4-2021-annie-coleman-melissa-english-gizelle-jean-english/
The Artist Images row has swiper with images off the page, however the prev/next arrows are not showing. On inspection I found the area is defined and being built properly. The problem is the :after on the buttons have a width of 0. My guess is the font is doing something weird but I don't know what. It doesn't show locally in my dev environment so it's definitely something in here. I am using 11ty to build these pages and pulling in version 6.6.1 if swiper from unpkg.com.
My Swiper markup carousel.njk
<div class="{{ swipeClass }}-swiper swiper-container">
<div class="swiper-wrapper">
{% for image in images %}
<div class="swiper-slide">
<img data-full-src="{{image.imageKitUrl}}" src="{{image.imageKitThumbUrl}}" alt="" onClick="openLightbox(this)">
{% if image.imageCredit %}
<div>{{ image.imageCredit[0].name }}</div>
{% endif %}
</div>
{% endfor %}
</div>
<div class="swiper-button-prev {{ swipeClass }}-prev"></div>
<div class="swiper-button-next {{ swipeClass }}-next"></div>
</div>
My Swiper script carousel.js
const swiperOptions = {
slidesPerView: 1,
spaceBetween: 10,
breakpoints: {
480: {
slidesPerView: 2,
spaceBetween: 20,
},
1024: {
slidesPerView: 3,
spaceBetween: 30,
},
},
centerInsufficientSlides: true,
};
if( null !== document.querySelector('.artist-swiper') ) {
const artistSwiper = new Swiper('.artist-swiper', {
...swiperOptions,
navigation: {
nextEl: '.artist-next',
prevEl: '.artist-prev',
}
});
}
if( null !== document.querySelector('.leslie-swiper') ) {
const leslieSwiper = new Swiper('.leslie-swiper', {
...swiperOptions,
navigation: {
nextEl: '.leslie-next',
prevEl: '.leslie-prev',
}
});
}
if( null !== document.querySelector('.location-swiper') ) {
const locationSwiper = new Swiper('.location-swiper', {
...swiperOptions,
navigation: {
nextEl: '.location-next',
prevEl: '.location-prev',
}
});
}

The answer was provided over on the swiper discussions on github. It was the text-rendering CSS property in my reset stylesheet. it was set to optimizeSpeed which disables ligatures and kerning.

Related

SwiperJS Lazy-Loading doesn't load images

I've followed these steps, but the images still won't load. I read somewhere, to load the swiper after the images are loaded. So I init the swiper after the data is successfully received. But are the images already loaded then?
<div class="swiper">
<div class="swiper-wrapper">
<div v-for="image in property.images" :key="image.id" class="swiper-slide">
<img :data-src="image.filePath" class="swiper-lazy" />
<div class="swiper-lazy-preloader"></div>
</div>
</div>
</div>
async fetch() {
try {
const property = await this.$axios.$get(
`/api/get-specific-property/${this.$route.params.id}`
)
if (property.success) {
this.property = property.data
this.initSwiper()
}
} catch (err) {
console.log(err)
}
},
methods: {
initSwiper() {
Swiper.use([Lazy]) // Not sure if it's really needed - saw this somewhere
this.swiper = new Swiper('.swiper', {
lazy: true,
preloadImages: false,
slidesPerView: 1,
loop: false,
})
}
}

GSAP animation not working with $ref in Nuxt

I am having an issue with a GSAP animation in a Nuxt build. The animation is to start when the
overlay navigation panel is brought into view with v-if="isMenuOpen". The nav works and shows as expected, but I want to animate the different items within the nav. The problem is GSAP isn't finding the items to animate. I've tried different approaches:
using TL.fromTo('.nav__panel-nav ul li a', { but this returns the error GSAP target .nav__panel-nav ul li a not found.
using TL.fromTo(this.$refs.li, { on both the components and wrapping HTML li element, which returns the error GSAP target undefined not found.
I'm new to working with Vue/Nuxt so i'm not sure o the best way to rectify the issue. Any direction on how to get this working, or a better approach would be appreciated.
<template>
<transition name="card">
<div class="nav" v-if="isMenuOpen">
<div class="nav__panel">
<div class="nav__panel-inner">
<div class="nav__panel-contact">
<div class="h-3">Contact Us</div>
<ul>
<li>
xxx
</li>
</ul>
<div class="nav__panel-social">
<SocialLinks />
</div>
</div>
</div>
</div>
<div class="nav__panel">
<div class="nav__panel-inner">
<nav class="nav__panel-nav">
<ul>
<li ref="li">
<NuxtLink to="/" ref="test">Home</NuxtLink>
</li>
<li>
<NuxtLink to="/about-us">About Us</NuxtLink>
</li>
<li>
<NuxtLink to="/our-expertise">Our Expertise</NuxtLink>
</li>
<li>
<NuxtLink to="/contact-us">Contact Us</NuxtLink>
</li>
</ul>
</nav>
</div>
</div>
</div>
</transition>
</template>
<script>
import { gsap } from "gsap";
export default {
computed: {
isMenuOpen() {
return this.$store.getters['navState'];
}
},
watch: {
isMenuOpen(val) {
if (val) {
document.getElementsByTagName('body')[0].classList.add('no-scroll');
this.animateNavIn();
} else {
document.getElementsByTagName('body')[0].classList.remove('no-scroll');
this.animateNavOut();
}
}
},
methods: {
animateNavIn() {
// https://blog.logrocket.com/animating-vue-with-greensock/
console.log('animate in');
const TL = gsap.timeline();
// TL.fromTo('.nav__panel-nav ul li a', {
TL.fromTo(this.$refs.li, {
duration: 1,
autoAlpha: 1,
y: '15px',
stagger: 0.05,
ease: "Power2.out"
},
{
autoAlpha: 1,
y: 0,
})
.to('.nav__panel-contact .h-3, li, .social__title, .social__links', {
duration: 1,
autoAlpha: 1,
y: 0,
stagger: 0.05,
ease: "Power2.out"
}, '-=.9');
},
animateNavOut() {
console.log('animate out');
// const TL = gsap.timeline();
// TL.to('.nav__panel-nav ul li a', {
// duration: 1,
// autoAlpha: 1,
// y: 0,
// stagger: 0.05,
// ease: "Power2.out"
// });
}
},
}
</script>
I've worked out what part of the issue is. The problem was with using v-if to render the nav. By using this, the elements I was trying to target weren't in the DOM so they couldn't be found. My solution was to use v-show instead. The difference is that an element with v-show will always be rendered and remain in the DOM; v-show only toggles the display CSS property of the element.
I am now able to target the HTML a tags using GSAP. I'm still not sure why $refs wouldn't work though...

Init Vue Awesome swiper on product card hover

ideally I need vue awesome swiper to init on product card hover, so until the user hovers, catalog loads only one img per product instead of multiple.
HTML
<div
#mouseover="handleMouseOver"
#mouseleave="handleMouseLeave"
/>
<div
v-if="media.length > 1"
ref="swiper"
v-swiper:mySwiper="swiperOption"
>
<div class="swiper-wrapper">
<div
v-for="image in images"
:key="image.id"
class="swiper-slide image__wrapper"
>
<img
:src="image.attributes.src"
:width="imgWidth"
:height="imgHeight"
:alt="imgAlt"
>
</div>
</div>
</div>
</div>
Component
data: () => ({
swiperOption: {
loop: true,
slidesPerView: 1,
centeredSlides: true,
spaceBetween: 30,
},
}),
methods: {
slideStart() {
if (this.$refs.swiper) {
this.mySwiper.activeIndex = 2;
this.mySwiper.autoplay.start();
}
},
slideStop() {
if (this.$refs.swiper) {
this.mySwiper.autoplay.stop();
this.mySwiper.activeIndex = 1;
}
},
handleMouseOver() {
this.isHovered = true;
this.slideStart();
},
handleMouseLeave() {
this.isHovered = false;
this.slideStop();
},
},
What I've tried and what problems encountered:
At first, I've added isHovered condition to v-if and used element in v-else, however after hover swiper refuses to autoplay (but reacts on activeIndex change)
After that I've tried adding init:false to swiperOption and this.$mySwiper.init() on hover, but it crashes whenever I'm trying to leave the page:
Would appreciate any ideas.
Solved by creating a parent div, and moving 'v-if' logic with hover condition there.

SwiperJS lazy loading - Image not displaying when using data-src as the guide says

I have been struggeling trying to implement SwiperJS to my Statamic 3 project.
I have a working carousel/slider that when not using data-src and lazy loading works perfectly fine. But as soon as I try to implement lazy loading following the guide on their website. I get either a white image/background with an infinite loader or a white image/background and no loader.
here is my code:
HTML (the images come from a antlers foreach):
<div class="flex flex-col w-1/3 p-2">
<div class="h-full w-full swiper-container">
<div class="h-48 swiper-wrapper">
{{ foreach:photos }}
<div class="swiper-slide">
<img data-src="{{ value:url }}" class="w-full h-full object-cover object-center swiper-lazy">
<div class="swiper-lazy-preloader"></div>
</div>
{{ /foreach:photos}}
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</div>
My JS:
// core version + navigation, pagination modules:
import Swiper, { Navigation, Pagination } from 'swiper';
import 'swiper/swiper-bundle.css';
// configure Swiper to use modules
Swiper.use([Navigation, Pagination]);
var mySwiper = new Swiper('.swiper-container', {
slidesPerView: 1,
spaceBetween: 0,
slidesPerGroup: 1,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
pagination: {
el: '.swiper-pagination'
},
mousewheel: false,
keyboard: true,
loop: true,
parallax: true,
grabCursor: true,
// Disable preloading of all images
preloadImages: false,
// Enable lazy loading
lazy: {
loadPrevNext: true,
},
});
Current result:
Anyone know why my images are not being rendered?
Kind regards,
Robbert
You need to import Lazy module.
Change
import Swiper, { Navigation, Pagination } from 'swiper';
to
import Swiper, { Navigation, Pagination, Lazy } from 'swiper';
and change
Swiper.use([Navigation, Pagination]);
to
Swiper.use([Navigation, Pagination, Lazy]);

Vuejs - Grab items passed to component template

So I have my markup looking like this:
<slider>
<img src="{{ gallery_image('HM722_Silver_Creek_9978.jpg', 'full') }}" alt="HM722 Silver Creek" style="margin-top:-15%;" />
<img src="{{ gallery_image('HM722_Silver_Creek_9978.jpg', 'full') }}" alt="HM722 Silver Creek" style="margin-top:-15%;" />
<img src="{{ gallery_image('HM722_Silver_Creek_9978.jpg', 'full') }}" alt="HM722 Silver Creek" style="margin-top:-15%;" />
<img src="{{ gallery_image('HM722_Silver_Creek_9978.jpg', 'full') }}" alt="HM722 Silver Creek" style="margin-top:-15%;" />
</slider>
It's using the slider component which you can see below:
var Slider = Vue.component('slider', {
template: '#homepage-slideshow',
replace: true,
data: {
current: 1,
speed: 1000,
margin: 0,
slideLength: 4
},
props: {
sliderWidth: 800,
slideWidth: 800,
height: 500,
dataSlide: 1
},
ready: function() {
this.sliderWidth = screen.width * 4;
this.slideWidth = screen.width;
this.height = screen.height;
console.log( this.img );
},
methods: {
thumbnailClick: function(e) {
var slide = $(e.target).data('slide');
var index = $('.slide').index( $('#' + slide) );
this.current = index + 1;
this.margin = this.slideWidth * (index);
this.animateSlides();
},
animateSlides: function() {
var self = this;
$('.slides').animate({
'margin-left': '-' + self.margin
}, self.speed, function() {
if( self.current === self.slideLength )
{
self.current = 1;
$('.slides').css('margin-left', 0);
}
});
}
}
});
The methods are still a mess so disregard those, but I want to try and do a v-repeat of the img tags being passed in since those will be looped through with a #foreach functionality. So there won't always be a definite 4.. The data attribute has a slideLength of 4 and the template has 4 areas, but what I REALLY want is to loop through whatever images are passed into the template.
Thanks for any direction.
I seemed to have gotten past this by passing a prop to the component like so:
<slider img-count="4">
And then accessing it with this.imgCount in my component. I don't know why I didn't think of this before!
Then in your component template after setting this.count = this.imgCount in your ready method:
<script type="text/x-template" id="homepage-slideshow">
<div class="slides" style="width:#{{ sliderWidth }}px">
<article v-repeat="count" id="slide#{{ $index }}" class="slide" style="width:#{{ slideWidth }}px;height:#{{ height }}px">
<content select="img:nth-of-type(#{{ $index + 1 }})"></content>
</article>
</div>
<div class="thumbnails">
<div class="thumbnail-wrapper container">
<img v-repeat="count" src="/img/thumbnail.png" data-slide="slide#{{ $index }}" v-on="click: thumbnailClick" style="height:#{{ thumbnailHeight }}px" />
</div>
</div>
</script>