Implementación de un Botón Interactivo con Efecto de Onda en Vue 3

En el desarrollo de interfaces de usuario modernas, los componentes nativos frecuentemente necesitan personalizaciones avanzadas para cumplir con directrices de diseño específicas. Un requerimiento habitual es la integración de microinteracciones, como un efecto visual de expansión al interactuar con un elemento. A continuación, se detalla la construcción de un componente de botón reutilizable utilizando Vue 3 y Composition API, incorporando una animación CSS dinámica de tipo pulso.

Definición del Componente

El siguiente código implementa un botón que gestiona estados de carga y deshabiltiado, delegando la lógica visual a los estilos. Se utiliza la sintaxis <script setup> para una gestión más eficiente del estado y los eventos.

<template>
  <button
    class="action-btn"
    :disabled="isDisabled"
    @click="triggerAction"
  >
    <span class="btn-label">{{ label }}</span>
  </button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  label: {
    type: String,
    required: true
  },
  isDisabled: {
    type: Boolean,
    default: false
  }
});

const emit = defineEmits(['action']);

const triggerAction = (event) => {
  if (!props.isDisabled) {
    emit('action', event);
  }
};
</script>

<style scoped>
.action-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 28px;
  font-size: 1rem;
  font-weight: 600;
  color: #ffffff;
  background-color: #0984e3;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  overflow: hidden;
  transition: background-color 0.25s ease, transform 0.1s ease;
  isolation: isolate;
}

.action-btn:active:not(:disabled) {
  transform: scale(0.98);
}

.action-btn:disabled {
  background-color: #b2bec3;
  color: #636e72;
  cursor: not-allowed;
}

.action-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  background-color: rgba(255, 255, 255, 0.4);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  z-index: -1;
  animation: ripple-effect 0.6s linear infinite;
  animation-play-state: paused;
}

.action-btn:hover:not(:disabled) {
  background-color: #0769b5;
}

.action-btn:hover:not(:disabled)::before {
  animation-play-state: running;
}

@keyframes ripple-effect {
  0% {
    width: 0;
    height: 0;
    opacity: 0.5;
  }
  100% {
    width: 350px;
    height: 350px;
    opacity: 0;
  }
}

.btn-label {
  position: relative;
  z-index: 1;
  pointer-events: none;
}
</style>

Análisis de la Arquitectura CSS

El comportamiento visual del componente se basa en la manipulación del contexto de apilamiento y el control de estados de animación mediante pseudo-clases.

  • Contexto de Apilamiento: Se emplea isolation: isolate en el contenedor principal para crear un nuevo contexto de apilamiento. Esto permite que el pseudo-elemento ::before se posicione con un z-index negativo, manteniéndose siempre por debajo del texto pero dentro de los límites del botón.
  • Confinamiento Visual: La propiedad overflow: hidden es fundamantal para recortar el efecto de onda circular a medida que sus dimensiones superan el tamaño del botón.
  • Máquina de Estados de Animación: En lugar de inyectar clases mediante JavaScript, la animación se controla puramente con CSS. El @keyframes ripple-effect define la expansión, pero se mantiene en pausa (animation-play-state: paused) por defecto. Únicamente cuando se cumple la condición :hover:not(:disabled), el motor de renderizado ejecuta la animación.
  • Accesibilidad y Estados: El estado :disabled anula las interacciones visuales y modifica la paleta de colores para indicar claramente la falta de disponibilidad al usuario.

Estrategia de Migración entre Frameworks

Al trabajar en ecosistemas diversos, a menudo es necesario portar componentes funcionales de un framework a otro (por ejemplo, de Vue a React). En lugar de reescribir manualmente la lógica de renderizado y el ciclo de vida, se pueden utilizar modelos de lenguaje de gran tamaño (LLM) para automatizar la traducción de sintaxis manteniendo la integridad funcional.

Para garantizar una conversión precisa de componentes modernos, el prompt debe ser altamente específico respecto a las convenciones del framework de destino. A continuación, se presenta un prompt optimizado para migrar el componente anterior a un componente funcional de React 18:

Actúa como un arquitecto de software frontend experto. Tu tarea es convertir el siguiente componente de Vue 3 (escrito con Composition API) a un componente funcional de React 18.

Requisitos técnicos estrictos:
1. Reemplaza la reactividad de Vue (defineProps, defineEmits) por la interfaz de props tipada de React.
2. Transforma la sintaxis de la plantilla a JSX válido.
3. Asegura que los eventos nativos (como onClick) manejen correctamente el estado `disabled` antes de invocar el callback.
4. Conserva el bloque de estilos CSS exactamente igual, asumiendo que se utilizará CSS Modules o un sistema de estilos en cascada similar.
5. Utiliza TypeScript para definir las interfaces de las propiedades.

Código fuente a convertir:
[Insertar código Vue aquí]

Etiquetas: vue.js CSS3 composition-api web-animation React

Publicado el 6-20 22:42