小強包裝器 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 偵測滑鼠位置。
座標與角度計算
- 中心點定位:計算元素中心相對於視窗的座標。
- 角度計算:以
Math.atan2計算元素中心 → 滑鼠的角度 。 - 反向探出:觸鬚設定在反方向(
)探出。 - 邊緣交點:透過射線與矩形邊界的交點公式,算出觸鬚在元素邊緣的精確位置。這能確保觸鬚無論從哪個角度探動,根部都能完美貼合元素邊緣。
距離與隱藏邏輯
計算滑鼠與元素邊框最近點的歐幾里得距離(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/s 與 3.1 rad/s 兩個不成整數比的頻率,能避免出現明顯的規律週期,讓動態更像真實生物。
2. 末段 (Tip Segment)
末段是一個阻尼驅動擺,由根段的角加速度(
txt
φ'' = -ωₙ² φ - 2ζωₙ φ' - θ_{root}''- 自然頻率 (
):決定末端的硬度與反應速度。 - 阻尼比 (
):欠阻尼狀態,使末端甩動後具有自然的收斂感。
原始碼
API
Props
interface Props {
/** 觸發觸鬚縮回的距離,單位 px。@default 150 */
hideDistance?: number;
}Slots
interface Slots {
default?: () => unknown;
}