skip to Main Content

I’m making an animated clickable gallery using Vue 3 transition-group.
Everything works fine except there is a small jump when the gallery slide goes from one side to the other, I’ve narrowed this down to being an issue with scaling the gallery panels as vue is not accounting for the extra distance when moving the item. This can be seen in the example below.

It may seem like an insignificant issue, but it becomes quite obvious compared to the non-scaled gallery, and is very noticeable with larger items as well as transition easing.

Is there a way to fix this? I’ve tried js transition hooks as well as changing every part of the transition to no avail.

Example

Here’s an example of the problem, you can slow down the slide animation to see the jump more clearly.

play.vuejs example

2

Answers


  1. Chosen as BEST ANSWER

    After a lot of digging and changes, I decided to simply remove transition-group entirely and rely on classes and styling to accomplish the same effect.

    There is currently no method to hook into the transition-group move transition which is what would be needed to fix this issue.

    Instead the item list is not filtered and instead items are hidden or removed with css, unfortunately this adds a render overhead for very large galleries compared to a filtered array but this is not an issue for my use case

    Working Example

    play.vuejs example


  2. This is related to how Vue handles the transition of scaled elements within a <transition-group>, which uses a "flip" technique to determine the starting and ending positions of elements and apply a "smooth" transition between them. When scaling is involved, the bounding box’s size and position change, which can throw off Vue’s internal calculations.

    To address this, you can try to utilize Vue’s transition hooks and some manual calculations to attempt a smoother transition. You’re mileage may vary depending, however.

    1. Use beforeEnter, enter, and afterEnter hooks to adjust the element’s transition.
    2. Override the default transition data with manual calculations accounting for scale.

    Integrate Hooks

    First, you need to integrate hooks into the ClickGallery component. I’ll include a generalized example of this.

    methods: {
      beforeEnter(el) {
        // Get initial position (before entering)
        const rect = el.getBoundingClientRect();
        el.dataset.initialTop = rect.top;
        el.dataset.initialLeft = rect.left;
      },
      enter(el, done) {
        // Get the final position (once it has entered)
        const finalRect = el.getBoundingClientRect();
    
        // Determine the distances for the transition
        const dx = el.dataset.initialLeft - finalRect.left;
        const dy = el.dataset.initialTop - finalRect.top;
    
        // Apply a reverse transition to the element (this will be the starting point)
        el.style.transform = `translate(${dx}px, ${dy}px) scale(0.9)`; // Assuming 0.9 is the scale factor
    
        // On the next frame, transition the element back to its natural position
        requestAnimationFrame(() => {
          el.style.transform = '';
          done();
        });
      },
      afterEnter(el) {
        el.style.transform = ''; // Clear the transform for good measure
      }
    }
    

    Now, include these hooks in the transition-group

    <transition-group
      name="slide-fade"
      tag="div"
      :before-enter="beforeEnter"
      :enter="enter"
      :after-enter="afterEnter"
    >
      <!-- gallery items here -->
    </transition-group>
    

    With this approach, we’re manually determining the starting and ending positions of the element, including its scale, and applying a reverse transition at the beginning. This gives the effect of the element sliding from its starting position to its final position, but with our manual calculations accounting for the scale.

    Vue’s internal mechanism might still attempt to handle the transition, so you may have to experiment a bit to get the exact effect you want. This should get you started in the right direction, however.

    Hope this helps!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search