蓄力按鈕 button
需要長按才能觸發的按鈕,按住時會出現進度條,進度滿了放開即觸發點擊。
進度滿後仍不放開,會有驚喜喔。(「・ω・)「
技術關鍵字
| 名稱 | 描述 |
|---|---|
| Pointer 事件 | 偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊 |
| SVG | 可在 DOM 中使用的圖形格式,適合複雜圖形和動畫,配合 Vue v-bind 可以實現基於資料的動態效果 |
| CSS 動畫 | 基於 CSS transition 和 animation 實現 |
| Anime.js | 輕量級 JavaScript 動畫函式庫 |
使用範例
基本用法
蓄力按鈕直到進度滿再放開,即可觸發 click 事件。
長按按鈕直到進度滿再放開
查看範例原始碼
vue
<template>
<div class="flex flex-col items-center gap-6">
<btn-charge
:label="t('label')"
@click="handleClick"
@explode="handleExplode"
@reset="handleReset"
/>
<div class="text-sm opacity-60">
<Transition
mode="out-in"
enter-active-class="transition-opacity duration-300"
leave-active-class="transition-opacity duration-150"
enter-from-class="!opacity-0"
leave-to-class="!opacity-0"
>
<span :key="message">
{{ message }}
</span>
</Transition>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BtnCharge from '../btn-charge.vue'
const { t } = useI18n()
const message = ref(t('hint'))
function handleClick() {
message.value = t('clicked')
}
function handleExplode() {
message.value = t('exploded')
}
function handleReset() {
message.value = t('hint')
}
</script>原理
以 Pointer Events 統一處理滑鼠與觸控。
按下時以 requestAnimationFrame 驅動進度,按鈕內部從底部往上填充亮色區塊,呈現水位上升效果。
觸控裝置因手指遮擋視線,額外在手指上方顯示圓餅進度 knob。
中途放開時,進度條以 outBounce 緩動回縮歸零;進度滿後放開則觸發 click。
進度滿後仍不放開會進入抖動階段,以 CSS @keyframes 產生隨機位移震動,強度隨時間遞增。
超過抖動時限後觸發爆炸,以 SVG clipPath 將按鈕切割成多塊四邊形碎片,再用 anime.js 讓碎片向四周飛散、旋轉、縮小並淡出,同時放射集中線強化衝擊感。ヽ(●`∀´●)ノ
原始碼
API
Props
interface Props {
/** 按鈕內文字 */
label?: string;
/** 是否停用 */
disabled?: boolean;
/** 同 html tabindex */
tabindex?: number | string;
/** 長按填滿所需時間(ms)。@default 1000 */
pressDuration?: number;
/** 進度滿後抖動多久會爆炸(ms)。@default 500 */
shakeDuration?: number;
/** 爆炸碎片行數。@default 4 */
rowCount?: number;
/** 爆炸碎片列數。@default 4 */
colCount?: number;
/** 爆炸後自動回復的延遲時間(ms),設為 0 或不設則不自動回復。@default 0 */
autoResetDelay?: number;
/** knob 圓餅直徑(px)。@default 30 */
knobSize?: number;
}Emits
const emit = defineEmits<{
/** 長按完成後放開時觸發 */
click: [];
/** 按鈕爆炸時觸發 */
explode: [];
/** 自動回復時觸發 */
reset: [];
}>()Methods
defineExpose({
/** 重置按鈕狀態 */
reset,
/** 手動觸發爆炸 */
explode,
})Slots
defineSlots<{
/** 按鈕 */
default?: () => unknown;
}>()