調皮的按鈕 button
停用時會越跑越遠的按鈕。ᕕ( ゚ ∀。)ᕗ
越想嚕他,就跑得越遠,和你家的貓一樣。(._.`)
使用範例
基本用法
當按鈕狀態為 disabled 並觸發 hover、click、key enter 事件時,按鈕會開始亂跑
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
<div class="flex flex-col gap-4 border rounded p-4">
<base-checkbox
v-model="disabled"
label="停用按鈕"
/>
<base-input
v-model="text"
placeholder="點擊這裡並使用 tab 將焦點轉移至按鈕後,再按下 Enter 看看"
class="w-full"
/>
</div>
<div class="flex justify-center">
<btn-naughty
label="調皮的按鈕"
class="font-bold"
:disabled="disabled"
z-index="30"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import BaseCheckbox from '../../base-checkbox.vue'
import BaseInput from '../../base-input.vue'
import BtnNaughty from '../btn-naughty.vue'
const text = ref('')
const disabled = ref(true)
</script>
移動距離
指定 maxDistanceMultiple 可以設定最大移動距離倍數(自身寬高倍數),若按鈕跑出指定範圍或超出畫面,都會自動回歸原點
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col items-center justify-center gap-4 border border-gray-300 p-6">
<base-input
v-model="maxMultiple"
type="number"
outlined
label="倍數"
/>
<btn-naughty
label="按鈕"
class="font-bold"
disabled
:max-distance-multiple="maxMultiple"
z-index="30"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import BaseInput from '../../base-input.vue'
import BtnNaughty from '../btn-naughty.vue'
const maxMultiple = ref(5)
</script>
呼叫 method
除了元件自身行為外,也可以直接呼叫 method 產生動作
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col items-center justify-center gap-4 border border-gray-300 p-6">
<div class="w-full flex gap-4 border rounded p-4">
<base-btn
label="移動"
@click="run"
/>
<base-btn
label="返回"
@click="back"
/>
</div>
<btn-naughty
ref="btn"
label="按鈕"
z-index="30"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import BaseBtn from '../../base-btn.vue'
import BtnNaughty from '../btn-naughty.vue'
const btn = ref<InstanceType<typeof BtnNaughty>>()
function run() {
btn.value?.run()
}
function back() {
btn.value?.back()
}
</script>
自訂按鈕
可以使用 default slot 自定義按鈕外觀
查看範例原始碼
vue
<template>
<div class="flex justify-center border border-gray-300 p-6">
<btn-naughty
disabled
z-index="30"
>
<div class="custom-button">
自定義按鈕
</div>
</btn-naughty>
</div>
</template>
<script setup lang="ts">
import BtnNaughty from '../btn-naughty.vue'
</script>
<style scoped lang="sass">
.custom-button
background: #ff8345
color: white
padding: 0.5rem 1.5rem
border-radius: 999rem
</style>
自訂拓印
你說拓印能不能自定義?可以啦,哪次不可以了。
使用 rubbing slot,自訂按鈕拓印內容
啪!跑了
自定義按鈕
查看範例原始碼
vue
<template>
<div class="flex justify-center border border-gray-300 p-6">
<btn-naughty
disabled
z-index="30"
>
<template #rubbing>
<div class="rubbing">
啪!跑了
</div>
</template>
<template #default>
<div class="btn">
自定義按鈕
</div>
</template>
</btn-naughty>
</div>
</template>
<script setup lang="ts">
import BtnNaughty from '../btn-naughty.vue'
</script>
<style scoped lang="sass">
.btn
padding: 0.5rem 1.5rem
background: #26A69A
border-radius: 999rem
font-weight: bold
color: white
cursor: pointer
.rubbing
padding: 0.5rem 1.5rem
background: #FEFEFE
border-radius: 999rem
border: 1px dashed #777
text-align: center
</style>
Slot Props
使用 slot prop 可以玩出更多花樣
😗
點此中獎
查看範例原始碼
vue
<template>
<div class="flex justify-center border border-gray-300 p-6">
<btn-naughty
disabled
z-index="30"
>
<template #rubbing="{ isRunning }">
<div class="rubbing">
{{ isRunning ? '😜' : '😗' }}
</div>
</template>
<template #default="{ isRunning }">
<div class="btn">
{{ isRunning ? '點不到咧' : '點此中獎' }}
</div>
</template>
</btn-naughty>
</div>
</template>
<script setup lang="ts">
import BtnNaughty from '../btn-naughty.vue'
</script>
<style scoped lang="sass">
.btn
padding: 0.5rem 1.5rem
background: #26A69A
border-radius: 999rem
font-weight: bold
color: white
font-size: 1.25rem
cursor: pointer
.rubbing
padding: 0.5rem 1.5rem
background: #FEFEFE
border-radius: 999rem
border: 1px dashed #777
text-align: center
font-size: 1.25rem
</style>
原理
滑鼠碰觸按鈕時,計算滑鼠位置到按鈕中心的單位向量,並以此向量為基準,移動一個按鈕尺寸的距離。
如果按鈕移動到畫面外,則會自動返回原點,使用 IntersectionObserver 實作。
注意!Σ(ˊДˋ;)
請不要將 overflow 設定為 hidden,否則按鈕一移動就會啪沒了,消失的無影無蹤。
原始碼
API
Props
interface Props {
/** 按鈕內文字 */
label?: string;
/** 是否停用 */
disabled?: boolean;
/** 同 CSS z-index */
zIndex?: number | string;
/** 最大移動距離,為按鈕尺寸倍數 */
maxDistanceMultiple?: number;
/** 同 html tabindex */
tabindex?: number | string;
}
Emits
const emit = defineEmits<{
(e: 'click'): void;
/** 開始移動時 */
(e: 'run'): void;
/** 開始返回時 */
(e: 'back'): void;
}>()
Methods
defineExpose({
/** 移動 */
run,
/** 返回原點 */
back,
/** 是否正在移動 */
isRunning,
})
Slots
defineSlots<{
/** 按鈕 */
default?: (props: { isRunning: boolean }) => unknown;
/** 拓印 */
rubbing?: (props: { isRunning: boolean }) => unknown;
}>()