Me gustaría crear un efecto de batido en una aplicación vue.js. Encontré un ejemplo, con el que puedo crear un efecto de sacudida con JavaScript, pero eventListener no se puede usar en vue.js, así que no sé cómo usar este código en vue.js.
¿Tiene alguna idea de cómo podría usar esta animación en vue.js sin un eventListener?
Aquí está el código, que quiero ajustar:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="./main.css"> <title>3d Vector Kata</title> <style> /* Standard syntax */ @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; } </style> </head> <body> <form id="test-form"> <input type="text" id="test-input"> <button type="submit" id="submit-button" onclick="shakeAnimation()">Submit</button> </form> <script src="./index.js"></script> </body> </html> <script> const input = document.querySelector("input#test-input"); const submit = document.querySelector("button#submit-button"); submit.addEventListener("click", (e) => { e.preventDefault(); if(input.value === "") { submit.classList.add("apply-shake"); } }); submit.addEventListener("animationend", (e) => { submit.classList.remove("apply-shake"); }); </script>Lo único que hace el detector de eventos en su ejemplo es alternar una clase.
Entonces puede usar la sintaxis de clase condicional <button :class="{'apply-shake': shake}"> ;
Compruebe en codesandbox: https://codesandbox.io/s/shake-effect-vue-71306745-z912ms?file=/src/App.vue
Así que puedes hacer algo así:
Editar: verifique la respuesta de @quadmachine que usa eventListener para animationend en lugar de 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>Sobre la base de la solución de @ Zecka, es aún mejor usar un detector de eventos en lugar de un tiempo de espera:
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> El uso de detectores de eventos en Vue no es un problema @ Florian27, puede apuntar fácilmente a cualquier elemento en su componente agregando el atributo ref o simplemente usando document.querySelector o incluso mejor this.$el.querySelector para que esté dentro del alcance de su componente y luego adjunte un detector de eventos usando JS puro.