Home > database >  How to specify a custom transition for QIntersection Quasar
How to specify a custom transition for QIntersection Quasar

Time:10-16

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:

  1. 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.
  2. q-intersection also wraps its contents in a div, which takes it one step deeper. This sometimes messes up my styling.
  3. 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 stating tag="div" doesn't help. For example when using flex and grid CSS classes.
  4. 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.

  • Related