Animate items in a list by staggering their appearance during the initial rendering

I am currently working on creating a navigation menu that has a staggered effect when the list items appear upon opening the menu.

Using a burger symbol to toggle the navigation menu to fullscreen, I want to incorporate an animation where each list item (links) appears with a delay relative to each other, starting from the top and working down to the bottom.

My initial approach was to utilize vue's <transition-group> along with list transitions, but the examples I found focused on adding/removing list items rather than staggering their appearance from the start.

I then came across: Vue.js: Staggering List Transitions, which seemed promising. However, I encountered difficulties implementing it successfully.

Do you have any insights or suggestions on how I can achieve this effect?

Currently, I am using v-if to render the navigation:

<transition name="u-anim-fade" mode="in-out">
  <Navigation v-if="navMenuOpen" />
</transition>

Within the Navigation component:

<nav>
    <ul class="Navigation__list">
      <li
        v-for="(item, key) in menu.items"
        class="Navigation__item"
        :key="`nav-item-${key}`">
        <nuxt-link>
          <span v-html="item.title" />
        </nuxt-link>
    </ul>
</nav>

(Some code has been omitted for brevity)

After trying to incorporate the enter/leave/onEnter functions as suggested in Vue.js: Staggering List Transitions

v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"

As shown below:

<nav>
    <transition-group
      name="staggered-fade"
      tag="ul"
      class="Navigation__list"
      v-bind:css="false"
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:leave="leave"
    >
      <li
        v-for="(item, key) in menu.items"
        class="Navigation__item"
        :key="`nav-item-${key}`">
        <nuxt-link>
          <span v-html="item.title" />
        </nuxt-link>
    </transition-group>
</nav>

The methods I added to the component were not being executed when rendering the Navigation component, most likely because the items were not being added or removed dynamically.

Answer №1

Maybe due to the lack of addition or removal of items.

Indeed, the solution you need is:

Adding Transitions on Initial Render

To include a transition on the initial render of a node, consider using the appear attribute:

<transition appear>
  <!-- ... -->
</transition>

After testing it I noticed that without it, the listener functions do not execute during the initial render.

Keep in mind that this method is also effective with <transition-group> components.

Answer №2

If you're a Vue 3 user and want to incorporate GSAP:

<template>
  <div>
    <transition-group 
      appear
      tag="ul"
      @before-enter="beforeEnter"
      @enter="enter"
    >
      <li v-for="(item, index) in items" :key="icon.name" :data-index="index">
        <div>{{ item.text }}</div>
      </li>
    </transition-group>
  </div>
</template>

<script>
import { ref } from 'vue'
import { gsap } from 'gsap'
export default {
  setup() {
    const items = ref([
      { text: 'by email' },
      { text: 'by phone' },
    ])
    const beforeEnter = (el) => {
      el.style.opacity = 0
      el.style.transform = 'translateY(100px)'
    }
    const enter = (el, done) => {
      gsap.to(el, {
        opacity: 1,
        y: 0,
        duration: 0.8,
        onComplete: done,
        delay: el.dataset.index * 0.2
      })
    }
    return { items, beforeEnter, enter }
  }
}
</script>

Discover more about this setup here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

D3.js is providing inaccurate tick numbers

Even though I specify that I want 3 ticks, I end up with 4 in my d3 js code The y-axis values I am working with are [2, 1, 3, 2, 4, 4, 6] svg .select(`[data-labels-y]`) .call(d3.axisLeft().scale(yScale).ticks(3).tickPadding(4))` My expected tick valu ...

Display a loader while waiting for an API call to complete within 5 seconds using Angular and RxJS operators. If the API call takes longer

We are actively working to prevent user blockage during file uploads by implementing a method in Angular using RxJS. How can I display a toastr message and hide the loader if the API does not complete within 5 seconds? uploadFile() { this.service.uploa ...

What is the process of invoking a function from a different component in Vue 3?

I attempted to use the $on method and this.$root.$refs.compname_component = this;, but encountered some errors. Please see my code below: formComponent.vue <template> <div v-if="showForm"> create Form </div> </templa ...

Unable to connect Dropzone to dynamically loaded DIV using AJAX

Using Dropzone for client-side image uploads has been a breeze. Take a look at this basic example that is currently up and running: If you examine the source code, you'll notice that I am utilizing JQuery to connect Dropzone to the upload1 div ID. H ...

The response from a Fetch API POST request comes back as a blank text

When I use fetch() to send a post request, the response is coming back empty. Here is my code: JS: async getTotalCompletionTimes() { var res = await fetch("repository/maps.php?method=getcompletiontimes&map="+this.getName(), {method: 'POST&ap ...

Tips for creating Vue test scenarios for a Vue component method using vue-test-utils and jest with a store dispatch feature

I'm currently writing Jest test cases for my Vue component. I have a method that calls the store dispatch function: dismissed() { this.$store.dispatch("alert/hideAlert"); }, In the test cases, I trigger the dismissed event like this and expect ...

Browsing through items within arrays to evaluate their values

I am facing an issue with two arrays that consist of objects. The first array contains restaurant objects with attributes such as name and averagePrice, while the second array has price objects (cheap, medium, expensive) with properties like label, lowEnd, ...

What is the best way to input data into the verified full name box?

.html file executed code <input type="name" [(model)]="x.name" class="form-control" pattern="[a-z]" > Greetings to the members of Stack, I am in need of assistance. I am relatively new to Angular and I am looking for a way to validate the full nam ...

Adjust the arrangement of divs when resizing the window

I have utilized flexbox to rearrange the boxes. Here is a link to the demo code My issue arises when resizing for smaller screens; I need to place B between A and C. https://i.stack.imgur.com/M0dpZ.png Any suggestions on achieving this goal? Thank you i ...

Mastering the correct way to handle the "window" object within the Node.js testing environment using JSDom

Testing my React app using Tape and JSDom involves importing a specific module at the beginning of each test JS file: import jsdom from 'jsdom' function setupDom() { if (typeof document === 'undefined') { global.document = jsdom ...

A new long polling AJAX request is triggered whenever there is a change in the parameter

function AjaxRequest(params, url) { if (params) { this.params = params; this.type = "GET"; this.url = url; // this.contentType = "multipart/form-data"; this.contentLength = params.length;; } } AjaxRequ ...

Challenge with the submission event listener

I am struggling to create my first event listener for the submit button that should respond to both a click and an enter key press. Currently, it is not working for either event, and I am unsure why. I do not intend to send any data to another page; I simp ...

Delete the right-hand p-timeline-event-opposite margin from the Angular 17 PrimeNG Timeline

I am currently utilizing the PrimeNG Timeline module to showcase a few straightforward horizontal timelines with content placed on the top side in a table format. How can I eliminate the space allocated by the .p-timeline-event-opposite section? Upon inspe ...

What is the best way to link this to a function in AngularIO's Observable::subscribe method?

Many examples use the Observable.subscribe() function in AngularIO. However, I have only seen anonymous functions being used like this: bar().subscribe(data => this.data = data, ...); When I try to use a function from the same class like this: update ...

Having issues with templateURL not working in AngularJS routeProvider

I've been experimenting with ngRoute and I'm facing an issue with templateURL not working as expected. The functionality works perfectly except for when I attempt to use templateURL. Here are the 4 files involved: test.html <p>{{test}}&l ...

JavaScript: What is the concept of overriding function named params?

function retrieveData({item1 = "blue", item2 = 7}) { console.log('theItems'); console.log(item1); console.log(item2); } retrieveData( { item1: 'pink', item2: 9 } ); I've come across conflicting i ...

Using Django, CSS, and Javascript, create a dynamic HTML form that shows or hides a text field based on the selection

How can I hide a text field in my Django form until a user selects a checkbox? I am a beginner in Django and web applications, so I don't know what to search for or where to start. Any guidance would be appreciated. Here is the solution I came up wi ...

Creating a table in VueJs and populating it with values retrieved from an MSSQL database in a .NET Core web application

I am developing a table within a .NET Core Web Application that includes multiple rows and columns filled with data retrieved from a MSSQL server through a WEB API Given the need for numerous rows and columns, I am considering using a for loop inside my & ...

Utilizing Three.js to Upload Images and Apply Them as Textures

While attempting to upload an image via URL and set it as a texture, I encountered an issue. The error message THREE.WebGLState: DOMException: Failed to execute 'texImage2D' on 'WebGLRenderingContext': Tainted canvases may not be loaded ...

Troubleshooting ng-click not functioning within ng-repeat with database integration in MEAN Stack

//app.js var blogApp = angular.module('BlogApp', []); blogApp.controller('BlogController', function($scope, $http){ $scope.createPost = createPost; $scope.deletePost = deletePost; function init(){ getAllPosts(); } init(); ...