Guide to animating Vuetify <v-badge /> when the state changes

Within the navigation bar, there is a "Cart" item that includes a <v-badge /> indicating the number of items in the cart. Whenever a user adds or removes an item from the cart, the count updates accordingly. However, I would like to add a visual effect where the badge bounces upon each state change to provide immediate feedback to the user. Despite my efforts by utilizing Vue documentation on animations and transitions, I have not been successful in achieving this effect.

I attempted to enclose the badge within a <transition /> element and apply certain keyframe animations sourced from CSS Tricks, but it still does not work as intended.

Here is the HTML structure:

        <v-tabs
          class="hidden-sm-and-down"
          optional>
          <v-tab
            v-for="(item, i) in items"
            :key="i"
            :exact="item.title === 'Home'"
            :to="item.to"
            :ripple="false"
            active-class="text--primary"
            class="font-weight-bold nav-link"
            min-width="96"
            nuxt
            text>
            <transition
              name="ballmove"
              enter-active-class="bouncein"
              leave-active-class="rollout">
              <v-badge
                v-if="item.badge && hasCartItems"
                color="red"
                :content="cartItems"
                :value="cartItems"
                class="default-badge"
                overlap>
                {{ item.title }}
              </v-badge>
              <span v-else>{{ item.title }}</span>
            </transition>
          </v-tab>
        </v-tabs>

The SCSS styling:

@mixin ballb($yaxis: 0) {
    transform: translate3d(0, $yaxis, 0);
  }

  @keyframes bouncein {
    1% { @include ballb(-400px); }
    20%, 40%, 60%, 80%, 95%, 99%, 100% { @include ballb() }
    30% { @include ballb(-80px); }
    50% { @include ballb(-40px); }
    70% { @include ballb(-30px); }
    90% { @include ballb(-15px); }
    97% { @include ballb(-10px); }
  }

  @keyframes rollout {
    0% { transform: translate3d(0, 300px, 0); }
    100% { transform: translate3d(1000px, 300px, 0); }
  }

  @keyframes ballroll {
    0% { transform: rotate(0); }
    100% { transform: rotate(1000deg); }
  }

  .rollout {
    width: 60px;
    height: 60px;
    animation: rollout 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
    div {
      animation: ballroll 2s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
    }
  }

  .bouncein {
    animation: bouncein 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
  }

  .ballmove-enter {
    @include ballb(-400px);
  }

Answer №1

Instead of using the <transition /> wrapper around the <v-badge />, I opted for a more traditional approach. I implemented a watch function like this:

    watch: {
      cartItems: function(newValue, oldValue) {
        const badge = document.querySelector('.v-badge__badge');
        if (newValue !== oldValue) {
          badge.classList.add('bounce');
          this.delay(500).then(() => {
            badge.classList.remove('bounce');
          });
        }
      }
    },

As for my SCSS styles:

 @mixin ballb($yaxis: 0) {
    transform: translate3d(0, $yaxis, 0);
  }

  @keyframes bouncein {
    0%, 50% { @include ballb(-3px); }
    25%, 75%, 100% { @include ballb() }
  }

  .bounce {
    animation: bouncein 500ms cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
  }

This approach achieved the desired "shake" effect for the badge. However, I am open to exploring more native Vue solutions if anyone has suggestions.

Answer №2

With the help of a valuable tip from @Bill Criswell, I was able to implement a subtle bounce effect in my Vue 2.6.11 project.

I learned that adding a :key attribute to the badge element would trigger a re-render, as suggested in this insightful Stack Overflow post. The remaining code was inspired by the examples provided in the official Vue.js documentation here.

<transition name="bounce">
   <v-badge
       :key="item.comments.length"
       v-if="item.comments && item.comments.length > 0"
       >
       <span slot="badge">
           {{ item.comments.length }}
       </span>
       <v-icon>mdi-comment </v-icon>
    </v-badge>
</transition>

I simply copied the associated SCSS code provided in the Vue example:

.bounce-enter-active {
  animation: bounce-in 0.5s;
}
.bounce-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

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

What strategies can I implement to ensure my modal dialog box remains responsive? Adjusting the window size causes the modal box to malfunction and lose its structure

Whenever I adjust the size of the browser window, the elements inside the modal box become misaligned. HTML <div class='modal'> <div class='modal-content'> </div> </div> Below is the CSS for the modal ...

Adjust the content column in the form to be mobile-friendly

Currently, I am coding in PHP and using Bootstrap. In my project, there are two columns - the LEFT column displays text, while the RIGHT column contains a form: Presently, when viewing on desktop, both columns are visible. However, on mobile devices, ...

Using .appendChild in Vue.js to dynamically add elements and then attaching v-model to them is a powerful combination

I am currently facing a challenge where I need to work with a library that does not have a Vue.js wrapper. This particular library dynamically appends elements in the DOM. My goal is to bind the v-model attribute to these dynamically appended elements usi ...

Ensure that when adjusting the height of a div, the content is always pushed down without affecting the overall layout of the page

My webpage contains a div element positioned in the middle of the content, with its height being adjustable through JavaScript code. I am seeking a way to manage the scrolling behavior when the height of the div changes. Specifically, I want the content t ...

Apply a distinct background color to every third list item following the first three list items

I have used CSS flex and width to design a list, and now I want to apply background colors to every 3 list items after the 3rd item. However, I would like the colors to appear in pairs of 2. I have attempted to achieve this using the CSS Pseudo Class :nth- ...

What is the best way to sort inertia data on the client-side?

Looking for a solution with my component that receives data, I have the following setup in my controller: route::get('/', function() { return inertia('foo', ['data' => Model::all()]) }); Within my Vue component: <templa ...

Launching a Nuxt.js Cloud Function

Is there a possibility to deploy a cloud function that allows for server-side rendering with Nuxt on Firebase? The issue lies in the fact that the Node version used on Firebase is 6.11.1 while the minimum required Node version for Nuxt versions 1 and above ...

What is the best way to superimpose an image onto a canvas?

I am working on a cool project where I have created a canvas that displays matrix binary code raining down. However, I would like to enhance it by adding an image overlay on top of the canvas. Here is my current setup: <div class="rain"> ...

What are the steps to transforming shorthand CSS into longhand?

Is there a tool available that can automatically convert shorthand CSS to longhand? I am in need of this functionality because I would like to utilize SmartSprites, which is not compatible with shorthand formatting. Additionally, if there is a tool that c ...

Changing alert variant dynamically with Vue.js and Bootstrap-Vue

As I work on a vue.js project using bootstrap-vue, I came across the following method to display an alert based on the documentation: <b-alert variant="success" show>Success Alert</b-alert> However, my attempt to achieve this is as follows: ...

Only referring to a CSS class within a particular element

I have defined the following CSS: .grade a{ color: white; } It is working, but maybe too well... Now, I have an HTML structure like this: <li class="grade"> <a><i class="fa fa-star fa-fw"></i></a> My Text < ...

Having trouble getting the jQuery slider to function properly

Can someone help me figure out how to make a slider work with jQuery? Here is the HTML code I am currently using: <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script src="http://aj ...

Assign a class to the checkbox of the first parent

I have a set of checkboxes generated using a for loop. I want the first checkbox to act as a parent, and all other checkboxes should act as children. When the parent checkbox is clicked, all child checkboxes should be checked. Although I have code to achi ...

Discovering a particular string within a jQuery array object: Tips and tricks

One thing that is confusing me is the jQuery array object. To explain further: I have two arrays, one called brandsLink and the other called floorLink. When a user clicks on a link, I am saving the brand name in a variable called brandName, and then checki ...

Incorporating SCSS into HTML files when they are situated at the same hierarchy

I have <h1 class='title home'> My Title </h1>, and to apply styles I can use the following CSS: .title { font-size: 1.95em; } .title .home { color: black; } While this method works, I a ...

What is the best way to rate a particular image?

while ($row = mysqli_fetch_array($result)) { echo ""; echo "<div id='img_div'>"; echo "<i class='fas fa-times'></i>"; echo "<img class='photoDeGallery' s ...

The alignment of the DIV elements is not as I had hoped

I currently have three different divs on my webpage. Two of them are background divs stacked on top of each other, while the third one contains content and is positioned within the lower background div. My issue arises when I try to make the content div co ...

Utilizing Django in conjunction with Vue to identify and address form validation errors

Utilizing a Django ModelForm with crispy forms for display on the template, upon completion of filling out the fields and clicking Submit, an email is triggered in the backend using Django's send_email functionality. However, the issue arises from th ...

Steps for adding a background image in ASP.NET MVC4

I recently removed the reference to the master page from the head section @{ Layout = null } After making changes in my CSS: html { background-image:url('Images\BGP.jpg'); } However, I didn't see any changes. Any suggesti ...

Implementing a transition to activate upon data loading in a Vue.js component – here's how!

Currently, I am immersed in a project utilizing vue.js and vue-router. Within my Vue application, I have a section dedicated to displaying news fetched from an API that functions as a blog. To load this news data into the component, I am utilizing the rou ...