Skip to content

小強包裝器 wrapper

被包裹的元素下方會探出兩根觸鬚... ( ・ิω・ิ)

技術關鍵字

名稱 描述
SVG可在 DOM 中使用的圖形格式,適合複雜圖形和動畫,配合 Vue v-bind 可以實現基於資料的動態效果
Pointer 事件偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊
向量計算處理方向、加速度、速度等等數學運算
CSS 動畫基於 CSS transition 和 animation 實現

使用範例

基本用法

靠近就會躲起來

查看範例原始碼
vue
<template>
  <div class="flex flex-col items-center gap-8 py-10">
    <wrapper-roachie>
      <base-btn
        class="!border-orange-300 !rounded-2xl !from-orange-400 !to-red-500 !bg-gradient-to-br !px-14 !py-6 !text-white !shadow-lg !shadow-orange-300/40 dark:!border-orange-500 dark:!shadow-orange-900/40"
        @click="handleBuy"
      >
        <span class="flex items-center gap-2 text-lg font-bold tracking-wide">
          {{ t('buyNow') }}
        </span>
      </base-btn>
    </wrapper-roachie>
  </div>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import BaseBtn from '../../base-btn.vue'
import WrapperRoachie from '../wrapper-roachie.vue'

const { t } = useI18n()

function handleBuy() {
  window.open('https://codlin.me', '_blank')
}
</script>

原理

useElementBounding 取得元素邊界,再以 useMouse 偵測滑鼠位置。

座標與角度計算

  1. 中心點定位:計算元素中心相對於視窗的座標。
  2. 角度計算:以 Math.atan2 計算元素中心 → 滑鼠的角度 θmouse
  3. 反向探出:觸鬚設定在反方向θmouse+π )探出。
  4. 邊緣交點:透過射線與矩形邊界的交點公式,算出觸鬚在元素邊緣的精確位置。這能確保觸鬚無論從哪個角度探動,根部都能完美貼合元素邊緣。

距離與隱藏邏輯

計算滑鼠與元素邊框最近點的歐幾里得距離(Euclidean distance):

ts
// 簡化後的計算邏輯
const dx = Math.max(left - mouseX, 0, mouseX - right)
const dy = Math.max(top - mouseY, 0, mouseY - bottom)
const distance = Math.sqrt(dx * dx + dy * dy)

當距離小於 hideDistance 時,isHiding 變為 true,觸鬚收回。

觸控體驗

在觸控裝置上,手指離開後 useMouse 的座標通常會停留在最後的位置。若該位置就在元素旁,觸鬚將永遠縮回。

為了解決此問題,加入了 Touch Idle 機制:

  • 偵測 touchstart 時重置閒置狀態。
  • 偵測 touchend 後啟動 2 秒的 debounce 計時器。
  • 若 2 秒內無新觸控,則強制進入閒置狀態,讓 isHiding 失效並重新彈出觸鬚。

響應式縮放

觸鬚尺寸會根據包裹元素的最短邊自動縮放(基準為 80px),確保在大按鈕或小標籤上都能維持視覺和諧:

ts
antennaScale = max(0.5, min(width, height) / 80)

觸鬚物理

一開始觸鬚只是兩條直線,用正弦波讓它左右搖擺。

看起來像兩根鐵棒在那邊晃,完全不像生物 (´・ω・`)

研究了一下,在擺動角度不大時,用雙擺模擬會更像。

根段主動搖擺,末段帶有物理慣性被動跟隨,這樣尖端就會有自然的延遲與甩動感。


鱈魚:「看起來更像小強觸鬚了!◝( •ω• )◟」

路人:「可以不要這麼專業的做這種鬼東西嗎?╭(°A ,°`)╮」


這部分實作於 roach-antenna.vue 中。

1. 根段 (Root Segment)

根段用兩個不同頻率的正弦波疊加,製造不規則的擺動:

ts
θ = (sin(t × 1.4 + φ₁) × 0.05 + sin(t × 3.1 + φ₂) × 0.02) × ampMult

使用 1.4 rad/s3.1 rad/s 兩個不成整數比的頻率,能避免出現明顯的規律週期,讓動態更像真實生物。

2. 末段 (Tip Segment)

末段是一個阻尼驅動擺,由根段的角加速度θroot )作為驅動力:

txt
φ'' = -ωₙ² φ - 2ζωₙ φ' - θ_{root}''
  • 自然頻率 ( ωn=2 ):決定末端的硬度與反應速度。
  • 阻尼比 ( ζ=0.45 ):欠阻尼狀態,使末端甩動後具有自然的收斂感。

原始碼

API

Props

interface Props {
  /** 觸發觸鬚縮回的距離,單位 px。@default 150 */
  hideDistance?: number;
}

Slots

interface Slots {
  default?: () => unknown;
}

v0.63.0