Skip to content

刮刮樂包裝器 wrapper

一秒變成刮刮樂 ヽ(́◕◞౪◟◕‵)ノ

技術關鍵字

名稱 描述
Pointer 事件偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊
SVG MaskSVG 遮罩效果,用於控制元素的顯示區域,可以實現複雜的形狀切割和遮罩

使用範例

基本用法

如同經典刮刮樂,可以刮除表面圖案

查看範例原始碼
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;
}>()

v0.54.1