Skip to content
歡迎來票選你最喜歡的元件! 也可以告訴我任何你想說的話喔!(*´∀`)~♥

蓄力按鈕 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;
}>()

v0.63.0