[Vuejs]-Shake effect in Vue

2👍

The only things that event listener do in your example is to toggle a class.
So you can use conditional class syntax <button :class="{'apply-shake': shake}">;

Check on codesandbox: https://codesandbox.io/s/shake-effect-vue-71306745-z912ms?file=/src/App.vue

So you can do something like that:

Edit: Check @quadmachine answer who use eventListener for animationend instead of setTimeout

<template>
  <div id="app">
    <button :class="{ 'apply-shake': shake }" @click="shakeAnimation()">
      Shake
    </button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      shake: false,
    };
  },
  methods: {
    shakeAnimation() {
      this.shake = true;
      setTimeout(() => {
        this.shake = false;
      }, 820); // timeout value depending on the duration of the animation
    },
  },
};
</script>

<style>
@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }

  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }

  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }

  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}

.apply-shake {
  animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}
</style>


2👍

Building on @Zecka’s solution, even better to use an event listener instead of a timeout:

https://codesandbox.io/s/shake-effect-vue-71306745-forked-hebrob?file=/src/App.vue:471-754

<script>
export default {
  data() {
    return {
      shake: false,
    };
  },
  mounted() {
    this.$refs.submit.addEventListener("animationend", () => {
      this.shake = false;
    });
  },
  methods: {
    shakeAnimation() {
      this.shake = true;
    },
  },
};
</script>

Using event listeners in Vue is not an issue @Florian27, you can target any element in your component easily by adding ref attribute or simply by using document.querySelector or even better this.$el.querySelector so that it’s scoped to your component and then attach an event listener using pure JS.

0👍

            //shake.css
            @keyframes shake {
              10%, 90% {
                  transform: translate3d(-1px, 0, 0);
              }
            
              20%, 80% {
                  transform: translate3d(2px, 0, 0);
              }
            
              30%, 50%, 70% {
                  transform: translate3d(-4px, 0, 0);
              }
            
              40%, 60% {
                  transform: translate3d(4px, 0, 0);
              }
            }
            
            .apply-shake {
              animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both !important;
            }
            
        //shake.js
        import '@/assets/css/shake.css';
        export const shake = app => {
          app.directive('shake', {
            mounted: el => {
              //节流
              let shakeOver = true;
              el.addEventListener(
                'click',
                e => {
                  if (shakeOver) {
                    shakeOver = false;
                    e.target.classList.add('apply-shake');
                    let timer = setTimeout(() => {
                      clearTimeout(timer);
                      e.target.classList.remove('apply-shake');
                      shakeOver = true;
                    }, 820);
                  }
                },
                false
              );
            }
          });
        };
        //main.js
        import { createApp } from 'vue';
        import App from './App.vue';
        
        import {shake} from '@/directives/shake.js'
        
        const app = createApp(App);
        shake(app);
        
        app.mount('#app');
    
    //please use vue3.x

//use example: 
<h1 v-shake>click me</h1>

Leave a comment