更新记录
v0.0.1(2025-11-28) 下载此版本
- vue3 ts重构,全屏适配
- 增加锤子移动和砸击动画
- 允许控制单次和多次砸金蛋
平台兼容性
uni-app(3.6.15)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | √ | - | - | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - |
这是一个基于 Vue 3 + TypeScript 的砸金蛋抽奖组件,重构自 egg-frenzy,在原有的抽奖组件上进行了一些改进。
使用示例
<template>
<view class="parent-container">
<egg-frenzy-vue3 :drawList="drawList" @showPrize="showPrizeModal" />
<!-- 优化后的弹窗 -->
<view v-if="isPrizeModalVisible" class="prize-modal">
<view class="modal-overlay" @click="closePrizeModal"></view>
<view class="prize-dialog">
<!-- 关闭按钮 -->
<view class="close-icon" @click="closePrizeModal">
<text class="close-text">✕</text>
</view>
<!-- 装饰元素 -->
<view class="decoration-stars">
<text class="star" v-for="i in 6" :key="i">✨</text>
</view>
<!-- 头部 -->
<view class="dialog-header">
<text class="congrats-text">🎊 恭喜中奖 🎊</text>
</view>
<!-- 内容区 -->
<view class="dialog-content">
<view class="image-wrapper">
<image :src="selectedPrize?.prizeImage" class="prize-image" mode="aspectFit" />
<view class="image-glow"></view>
</view>
<text class="prize-label">获得奖励</text>
<text class="prize-name">{{ selectedPrize?.prizeName }}</text>
<!-- 操作按钮 -->
<button @click="closePrizeModal" class="confirm-btn">
<text class="btn-text">开心收下</text>
</button>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from "vue";
import EggFrenzyVue3 from "@/components/egg-frenzy-vue3/egg-frenzy-vue3.vue";
const drawList = ref([
{
sort: 1,
prizeName: "一等奖",
prizeImage: "https://example.com/prize1.png ",
isOpen: false,
},
{
sort: 2,
prizeName: "二等奖",
prizeImage: "https://example.com/prize2.png ",
isOpen: false,
},
{
sort: 3,
prizeName: "三等奖",
prizeImage: "https://example.com/prize3.png ",
isOpen: false,
},
{
sort: 4,
prizeName: "谢谢参与",
prizeImage: "https://example.com/prize4.png ",
isOpen: false,
},
{
sort: 5,
prizeName: "特等奖",
prizeImage: "https://example.com/prize5.png ",
isOpen: false,
},
{
sort: 6,
prizeName: "幸运奖",
prizeImage: "https://example.com/prize6.png ",
isOpen: false,
},
]);
const isPrizeModalVisible = ref(false);
const selectedPrize = ref(null);
const showPrizeModal = (prize) => {
selectedPrize.value = prize;
isPrizeModalVisible.value = true;
};
const closePrizeModal = () => {
isPrizeModalVisible.value = false;
selectedPrize.value = null;
};
</script>
<style scoped>
.parent-container {
height: 100vh;
display: flex;
justify-content: center;
position: relative;
}
/* 弹窗背景遮罩 */
.prize-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
.modal-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
animation: fadeIn 0.3s ease;
}
.prize-dialog {
position: relative;
width: 85%;
max-width: 420px;
background: linear-gradient(135deg, #ff4757 0%, #ff3838 100%);
border-radius: 24px;
overflow: hidden;
box-shadow: 0 20px 40px rgba(255, 71, 87, 0.3);
animation: bounceIn 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.close-icon {
position: absolute;
top: 20px;
right: 20px;
width: 25px;
height: 25px;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
cursor: pointer;
transition: all 0.3s ease;
}
.close-text {
font-size: 14px;
color: #ff4757;
font-weight: bold;
line-height: 1;
}
.close-icon:active {
transform: scale(0.95);
background: #fff;
}
.decoration-stars {
position: absolute;
top: -20px;
left: 0;
right: 0;
height: 60px;
display: flex;
justify-content: space-around;
pointer-events: none;
}
.star {
font-size: 24px;
color: #fff;
opacity: 0.8;
animation: twinkle 2s infinite;
}
.star:nth-child(2n) {
animation-delay: 0.5s;
}
.star:nth-child(3n) {
animation-delay: 1s;
}
.dialog-header {
padding: 30px 20px 20px;
text-align: center;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, transparent 100%);
}
.congrats-text {
font-size: 28px;
font-weight: bold;
color: #fff;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
letter-spacing: 2px;
}
.dialog-content {
padding: 0 30px 30px;
text-align: center;
}
.image-wrapper {
position: relative;
width: 160px;
height: 160px;
margin: 0 auto 20px;
}
.prize-image {
width: 100%;
height: 100%;
border-radius: 50%;
border: 6px solid #fff;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
position: relative;
z-index: 2;
background: #fff;
}
.image-glow {
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background: radial-gradient(circle, rgba(255, 215, 0, 0.4) 0%, transparent 70%);
border-radius: 50%;
animation: pulse 2s infinite;
}
.prize-label {
display: block;
font-size: 16px;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 8px;
letter-spacing: 1px;
}
.prize-name {
display: block;
font-size: 32px;
font-weight: bold;
color: #fff;
margin-bottom: 30px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.confirm-btn {
width: 100%;
padding: 0 16px;
background: linear-gradient(135deg, #ffd700 0%, #ffc400 100%);
border: none;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(255, 215, 0, 0.3);
transition: all 0.3s ease;
}
.confirm-btn:active {
transform: scale(0.98);
box-shadow: 0 2px 6px rgba(255, 215, 0, 0.3);
}
.btn-text {
font-size: 18px;
font-weight: bold;
color: #d63031;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes bounceIn {
0% {
transform: scale(0.3);
opacity: 0;
}
50% {
transform: scale(1.05);
}
70% {
transform: scale(0.95);
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes twinkle {
0%,
100% {
opacity: 0.8;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.2);
}
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 0.6;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
100% {
transform: scale(1);
opacity: 0.6;
}
}
</style>
Props 属性说明
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
drawList |
Array<PrizeItem> |
- | 是 | 奖品数据列表,最多 6 个 |
singleMode |
boolean |
true |
否 | 是否单抽模式(true 只砸一次,false 可砸多次) |
数据格式
interface PrizeItem {
sort: number; // 金蛋排序号(1-6)
prizeName: string; // 奖品名称
prizeImage: string; // 奖品图片 URL
isOpen?: boolean; // 是否已打开
}
示例数据:
const drawList = [
{
sort: 1,
prizeName: "一等奖",
prizeImage: "https://example.com/prize1.png",
isOpen: false
},
// ...最多 6 个
]
Events 事件
| 事件名 | 回调参数 | 触发时机 | 说明 |
|---|---|---|---|
showPrize |
(item: PrizeItem, index: number) |
金蛋打开后 | 返回打开的奖品数据和索引,用于展示奖品弹窗 |
附加说明
- 图片预加载:组件会自动预加载金蛋、锤子图片,确保网络畅通
- 单抽模式限制:singleMode=true 时,砸开一个金蛋后其他金蛋会变暗且不可点击
常见问题
Q1: 锤子不循环高亮? A: 检查 drawList 中 isOpen 是否全为 true,或 remainingCount 为 0
Q2: 如何控制抽奖次数? A: 当前逻辑内置 remainingCount=6,可在源码中调整
Q3: 单抽模式下如何重置? A: 修改 drawList 中所有项的 isOpen 为 false,并重新渲染组件

收藏人数:
下载插件并导入HBuilderX
赞赏(0)
下载 7
赞赏 0
下载 11501388
赞赏 1813
赞赏
京公网安备:11010802035340号