Skip to content

求關注的按鈕 button

很會刷存在感的按鈕!◝( ゚ ∀。)◟

技術關鍵字

名稱 描述
Pointer 事件偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊
CSS 動畫基於 CSS transition 和 animation 實現
JS 動畫基於 JavaScript 實現的動畫,達成更複雜、精準的動畫控制,常見套件有 GSAP、anime.js 等
Anime.js輕量級 JavaScript 動畫函式庫

使用範例

基本用法

滑鼠靠近按鈕時會跑過來,若不在畫面內則會擠到邊緣湊熱鬧。

鱈魚 冷凍櫃長期住民
歡迎來到全球(自稱)最專業的鱈魚介紹網站。這裡沒有網美開箱,只有一條條 正在思考「自己適合被煎、被炸,還是被清蒸」的人生規劃中的鱈魚。
鱈魚,海洋界的鹹水奇才,上岸後搖身一變成炸魚薯條裡的夢幻男一號。 牠的夢想很單純——有朝一日能被做成外酥內嫩、筋道不柴的鱈魚排, 而不是永遠躺在冷凍櫃裡,當你逛賣場時視而不見的背景板。
身分證資料
學名:Gadus morhua
暱稱:鱈魚、炸魚薯條主角
居住地:冷水海域 & 冷凍櫃
個性特徵
  • 味道溫柔,不搶戲
  • 肉質細緻,沒刺好相處
  • 適合配任何醬,交際手腕一流
人生目標
  • 當一份被拍照打卡的主餐
  • 進營養師的推薦清單
  • 不要再被誤認成多利魚
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6 shadow-sm">
    <div class="flex flex-col gap-4">
      <div class="flex items-center gap-2 text-xl font-bold">
        <span>鱈魚</span>
        <span class="border border-sky-100 rounded-full px-2 py-0.5 text-sm text-sky-600 font-normal">
          冷凍櫃長期住民
        </span>
      </div>

      <div class="opacity-80">
        歡迎來到全球(自稱)最專業的鱈魚介紹網站。這裡沒有網美開箱,只有一條條
        正在思考「自己適合被煎、被炸,還是被清蒸」的人生規劃中的鱈魚。
      </div>

      <div class="py-6 leading-relaxed opacity-80">
        鱈魚,海洋界的鹹水奇才,上岸後搖身一變成炸魚薯條裡的夢幻男一號。
        牠的夢想很單純——有朝一日能被做成<b>外酥內嫩、筋道不柴的鱈魚排</b>,
        而不是永遠躺在冷凍櫃裡,當你逛賣場時視而不見的背景板。
      </div>

      <div class="grid grid-cols-1 gap-4 text-sm md:grid-cols-3">
        <div class="border border-slate-100 rounded-lg p-4">
          <div class="text-xs font-semibold opacity-80">
            身分證資料
          </div>
          <div class="mt-1">
            <div>學名:<span class="text-xs font-mono">Gadus morhua</span></div>
            <div>暱稱:鱈魚、炸魚薯條主角</div>
            <div>居住地:冷水海域 & 冷凍櫃</div>
          </div>
        </div>

        <div class="border border-slate-100 rounded-lg p-4">
          <div class="text-xs font-semibold opacity-80">
            個性特徵
          </div>
          <ul class="mt-1 list-disc list-inside space-y-1">
            <li>味道溫柔,不搶戲</li>
            <li>肉質細緻,沒刺好相處</li>
            <li>適合配任何醬,交際手腕一流</li>
          </ul>
        </div>

        <div class="border border-slate-100 rounded-lg p-4">
          <div class="text-xs font-semibold opacity-80">
            人生目標
          </div>
          <ul class="mt-1 list-disc list-inside space-y-1">
            <li>當一份被拍照打卡的主餐</li>
            <li>進營養師的推薦清單</li>
            <li>不要再被誤認成多利魚</li>
          </ul>
        </div>
      </div>
    </div>

    <div class="mt-4 flex justify-center">
      <btn-attention-seeker
        label="點我購買"
        :top-offset="topOffset"
        z-index="19"
        @click="handleClick"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { useElementSize, useWindowSize } from '@vueuse/core'
import { computed, onMounted, reactive, ref } from 'vue'
import BtnAttentionSeeker from '../btn-attention-seeker.vue'

const windowSize = reactive(useWindowSize())

const navRef = ref<HTMLHeadElement>()
const localNavRef = ref<HTMLDivElement>()
onMounted(() => {
  navRef.value = document.querySelector<HTMLHeadElement>('.VPNav') ?? undefined
  localNavRef.value = document.querySelector<HTMLDivElement>('.VPLocalNav') ?? undefined
})

const navEl = reactive(useElementSize(navRef))
const localNavEl = reactive(useElementSize(localNavRef))

const topOffset = computed(() => {
  if (windowSize.width < 960) {
    return localNavEl.height ?? 0
  }
  return (navEl.height ?? 0) + (localNavEl.height ?? 0)
})

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

原理

按鈕移動容器(carrierRef)會隨著滑鼠位置移動,並且在視窗邊界時會擠到邊緣湊熱鬧。

原始碼

API

Props

interface Info {
  width: number;
  height: number;
  x: number;
  y: number;
}

interface Props {
  /** 按鈕內文字 */
  label?: string;
  /** 是否停用 */
  disabled?: boolean;
  /** 同 CSS z-index */
  zIndex?: number | string;
  /** 跟隨距離,當距離小於此值時開始跟隨 */
  followDistance?: number | ((info: Info) => number);
  /** 上方偏移量,避免被 header 遮擋 */
  topOffset?: number;
  /** 下方偏移量,避免被 footer 遮擋 */
  bottomOffset?: number;
}

Slots

defineSlots<{
  /** 按鈕 */
  default?: () => unknown;
}>()

v0.51.0