I have been using QIntersection on Quasar to apply transitions to elements when they are scrolled into the viewport. Lately, I have been feeling the need to specify my own transitions/animations which I define via CSS. At first I used v-intersection
directive, managing state manually. That got complex and tedious real fast.
Is there a way to specify my custom CSS transition class in the transition
prop, or am I locked in to Quasar embedded ones?
<q-intersection transition="CustomCSSclass?" transition-duration="250">
<!-- My element goes here -->
<q-intersection>
CodePudding user response:
If we are talking about Quasar 2 (current release version)...
There is no official way how to use custom transition with components using transition
prop (expecting "build-in" transition)
BUT Quasar uses pretty simple system when resolving those transition:
h(Transition, {
name: 'q-transition--' props.transition
}, getContent)
So for example slide-right
transition is using CSS classes .q-transition--slide-right
[ -enter-active
, -leave-active
etc.). Source
So what you need is to create your own transition CSS classes with the correct name and just use it as if they were build-in Quasar transitions.
CodePudding user response:
Thanks @michal-levý for pointing me in the right direction. I followed that route but I had to come up with my own custom solution to suit my needs.
Problems I ran into with q-intersection.
What I originally wanted to achieve was making elements animate (play transition) when they are scrolled into the viewport.
I started using the q-intersection
component. It works well in some cases and in other cases it doesn't, for the following reasons:
q-intersection
adds an extra tag every time, hence more code. It makes my code less readable yet it does not serve an obvious function.q-intersection
also wraps its contents in a div, which takes it one step deeper. This sometimes messes up my styling.q-intersection
does not respond well to my CSS. CSS that normally works on divs and takes mere seconds to write, fails for some reason. Even explicitly statingtag="div"
doesn't help. For example when using flex and grid CSS classes.- Multiple
q-intersection
tags within the same row/parent container can lead to unexpected behavior such as screen flicker or other elements around resizing during animation.
My custom solution
After experiencing the hitches mentioned above, I decided to remove the q-intersection
wrapper altogether and use the v-intersection
directive directly.
I defined the transitions/animations in the data-transition
attribute. More on data-* attributes. Then I set the v-intersection directive to a composable I created, that adds and removes the transition classes based on the entry.isIntersecting
value (boolean). The code looks like this (short demo):
<template>
<div
@click="scrollToContent"
data-transition="bounceTwice"
v-intersection="useAnimate"
>
<span >Learn more</span>
<q-icon name="ion-ios-arrow-down" />
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { useAnimate } from 'src/composables/animate'
export default defineComponent({
name: 'Showcase',
setup () {
const scrollToContent = () => {
document.getElementById('content')?.scrollIntoView({
behavior: 'smooth',
block: 'start'
})
}
return {
scrollToContent, useAnimate
}
}
})
</script>
The animate composable src/composables/animate.ts
:
export const useAnimate = (entry: IntersectionObserverEntry) => {
// Get target element's transition classes (space separated if more than one)
const transition = (entry.target as HTMLElement).dataset.transition as string
// If element is in view, add transition classes
if (entry.isIntersecting) {
entry.target.classList.add(...transition.split(' '))
} else {
// If element is not in view, remove transition classes
entry.target.classList.remove(...transition.split(' '))
}
}
This solution is so lightweight and hassle-free. Works well so far.