Agile Button button
An extremely agile button ◝( •ω• )◟
Inspired by the Doro meme collaboration from Stellar Blade — the first time I saw it, I couldn't stop laughing. (´,,•ω•,,)
Usage Examples
Basic Usage
When disabled, triggering the button makes it dodge at ultra-high speed. ─=≡Σ((( つ•̀ω•́)つ
View example source code
<template>
<div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6">
<div class="flex flex-col gap-4 border rounded">
<base-checkbox
v-model="disabled"
:label="t('disableButton')"
class="p-4"
/>
</div>
<div class="flex justify-center">
<btn-agile
:label="t('clickMe')"
:disabled="disabled"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import BtnAgile from '../btn-agile.vue'
const { t } = useI18n()
const disabled = ref(true)
</script>Form Example
Can't click it until you fill out the form! (╯•̀ὤ•́)╯
View example source code
<template>
<div class="relative w-full flex justify-center border border-gray-200 rounded-xl p-6 py-24">
<div class="max-w-[20rem] flex flex-col gap-4">
<base-input
v-model="form.username"
:label="t('帳號 *')"
class="w-full"
/>
<base-input
v-model="form.password"
type="password"
:label="t('密碼 *')"
class="w-full"
/>
<div class="mt-3 flex justify-center">
<btn-agile
:label="t('登入')"
:disabled
z-index="30"
@click="handleSubmit"
/>
</div>
</div>
<transition name="opacity">
<div
v-if="isSubmitted"
class="absolute inset-0 z-[40] flex flex-col items-center justify-center gap-6 rounded-xl bg-slate-600 bg-opacity-90 text-white"
@click="reset"
>
<span class="text-xl tracking-wide">
{{ t('表單已送出!(*´∀`)~♥') }}
</span>
<span class="cursor-pointer text-xs">
{{ t('點一下再來一次') }}
</span>
</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseInput from '../../base-input.vue'
import BtnAgile from '../btn-agile.vue'
const { t } = useI18n()
const form = ref({
username: '',
password: '',
})
const disabled = computed(() => {
return form.value.username === '' || form.value.password === ''
})
const isSubmitted = ref(false)
function handleSubmit() {
if (disabled.value) {
return
}
isSubmitted.value = true
}
function reset() {
isSubmitted.value = false
form.value = {
username: '',
password: '',
}
}
</script>
<style lang="sass" scoped>
.rubbing
padding: 0.75rem
color: #ff7530
opacity: 0.8
border: 1px dashed #ff7530
border-radius: 0.2rem
white-space: nowrap
text-align: center
.opacity-enter-active, .opacity-leave-active
transition-duration: 0.4s
.opacity-enter-from, .opacity-leave-to
opacity: 0 !important
</style>How It Works
This time we use the trendy Motion library to implement the button animation. ( •̀ ω •́ )✧
Motion leverages hardware acceleration whenever possible, and the Vue version deeply integrates with the reactivity system, delivering excellent performance. It also comes with many useful built-in components.
Highly recommended reading: The Web Animation Performance Tier List
It provides a detailed introduction to the performance characteristics of various animation techniques and Web animation knowledge — quite interesting.
Source Code
API
Props
interface Props {
/** 按鈕內文字 */
label?: string;
/** 是否停用 */
disabled?: boolean;
/** 同 CSS z-index */
zIndex?: number | string;
/** 同 html tabindex */
tabindex?: number | string;
}Emits
const emit = defineEmits<{
(e: 'click'): void;
}>()Methods
defineExpose({})Slots
defineSlots<{
/** 按鈕 */
default?: () => unknown;
}>()