刮刮樂包裝器 wrapper
一秒變成刮刮樂 ヽ(́◕◞౪◟◕‵)ノ
技術關鍵字
| 名稱 | 描述 |
|---|---|
| Pointer 事件 | 偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊 |
| SVG Mask | SVG 遮罩效果,用於控制元素的顯示區域,可以實現複雜的形狀切割和遮罩 |
使用範例
基本用法
如同經典刮刮樂,可以刮除表面圖案
100.00%
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6">
<wrapper-scratch-off
ref="scratchOffRef"
class="h-[40vh] w-full"
@update:remain-ratio="(value) => handleUpdateRemainRatio(value)"
>
<div
class="relative h-full w-full flex flex-col select-none items-center justify-center gap-4 border p-4"
:class="{ ' pointer-events-none': remainRatioNumber > 85 }"
>
<a
href="https://codlin.me/article-overview.html"
target="_blank"
class="text-xl font-bold duration-300"
:class="{ ' opacity-20': remainRatioNumber > 85 }"
>
恭喜中獎!點我領獎!ლ(´ڡ`ლ)
</a>
<div
class="text-xs opacity-70 duration-300"
:class="{ ' !opacity-0': remainRatioNumber <= 85 }"
>
刮太少了,請繼續刮
</div>
<a
href="https://165.npa.gov.tw/"
target="_blank"
class="absolute bottom-0 right-0 p-2 text-xs opacity-0 duration-500"
:class="{ '!opacity-100': remainRatioNumber <= 70 }"
>
騙你的,點我才可以領獎ヽ(́◕◞౪◟◕‵)ノ
</a>
</div>
</wrapper-scratch-off>
<div class="text-center text-2xl font-bold">
{{ remainRatio }}%
</div>
<base-btn
label="重置"
@click="handleReset"
/>
</div>
</template>
<script setup lang="ts">
import { animate } from 'animejs-v4'
import { computed, ref, useTemplateRef } from 'vue'
import BaseBtn from '../../base-btn.vue'
import WrapperScratchOff from '../wrapper-scratch-off.vue'
const remainRatio = ref('100.00')
const remainRatioNumber = computed(() => Number.parseFloat(remainRatio.value))
function handleUpdateRemainRatio(value: number) {
animate(remainRatio, {
value: value * 100,
duration: 300,
modifier: (value) => value.toFixed(2),
})
}
const scratchOffRef = useTemplateRef('scratchOffRef')
function handleReset() {
scratchOffRef.value?.reset()
}
</script>原理
為了實現自定義遮罩,所以使用 SVG Mask 實現刮除效果,搭配 Canvas 計算刮除比例。
原始碼
API
Props
interface Props {
/** 刮除比例。用於 v-model 綁定 */
remainRatio?: number;
/** 刮痕寬度 */
strokeWidth?: number;
/** 觸發刮除方式,hover 或按著不放 */
triggerScratchOffMode?: 'hover' | 'hold';
}Emits
const emit = defineEmits<{
'update:remainRatio': [value: number];
}>()Methods
defineExpose({
reset,
/** 刮除比例 */
remainRatio,
})Slots
defineSlots<{
mask?: () => unknown;
default?: () => unknown;
}>()