微信小程序实战:幸运抽奖小程序
一、项目介绍
1.1 项目简介
本项目是一款基于微信小程序的蓝粉色梦幻风盲盒幸运抽奖系统,模拟商场线下抽奖活动场景。摒弃传统大转盘样式,采用当下流行的福袋盲盒抽奖交互,界面采用清新蓝粉色渐变主题,搭配漂浮动画、毛玻璃卡片、渐变按钮,整体美观、年轻化、吸引力强。项目完整实现了抽奖业务逻辑、页面动态交互、数据绑定、定时器动画、页面传参等小程序核心技术点。空白代码包和图片文件已在顶部的链接给出,可自行下载学习。
1.2 功能介绍
蓝粉色全局主题UI:导航栏、背景、按钮统一蓝粉渐变风格
福袋盲盒抽奖:抽奖过程福袋左右晃动动画
双按钮控制:开始抽奖、停止开奖
抽奖次数限制:每日默认3次抽奖机会
动态状态提示:空闲/抽奖中文字动态切换
奖品结果页展示:展示奖品图片、奖品名称、奖品描述
抽奖规则弹窗:点击弹窗展示活动说明
全局漂浮装饰动画:爱心、星星、光点浮动特效
效果展示:
1.3 项目目录结构
项目根目录 ├─ images # 抽奖所需图片资源 │ ├─ box.png # 福袋盲盒图片 │ ├─ p1.png # 一等奖 │ ├─ p2.png # 二等奖 │ ├─ p3.png # 三等奖 │ ├─ p4.png # 参与奖 │ ├─ p5.png # 幸运奖 │ ├─ p6.png # 纪念奖 │ ├─ p7.png # 购物奖 │ └─ p8.png # 谢谢参与 ├─ pages │ ├─ index # 抽奖首页 │ └─ result # 抽奖结果页 ├─ app.js # 全局逻辑 ├─ app.json # 全局配置 └─ app.wxss # 全局样式二、完整可运行代码 + 逐文件知识点讲解
2.1 app.json 全局配置文件
功能:注册页面、配置导航栏整体样式、主题颜色
{ "pages": [ "pages/index/index", "pages/result/result" ], "window": { "navigationBarBackgroundColor": "#FFA1D9", "navigationBarTitleText": "幸运抽奖小程序", "navigationBarTextStyle": "white" }, "style": "v2", "sitemapLocation": "sitemap.json" }知识点 & 用到的API
pages:小程序页面注册,数组第一个为默认首页
navigationBarBackgroundColor:导航栏背景色(蓝粉色主题)
navigationBarTitleText:导航栏标题文字
navigationBarTextStyle:导航文字颜色仅支持 black / white
style:v2:启用小程序新版样式渲染
2.2 app.wxss 全局样式文件
功能:统一全局背景、布局、清除默认样式,实现蓝粉渐变全局背景
page { margin: 0; padding: 0; background: linear-gradient(135deg, #A8E6FF 0%, #FFD1F0 100%); min-height: 100vh; font-family: "PingFang SC","Microsoft YaHei",sans-serif; } .container { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40rpx; min-height: 100vh; position: relative; } button::after { border: none; }知识点
linear-gradient:CSS渐变背景,实现蓝粉梦幻配色
Flex 垂直居中布局:页面内容居中显示
rpx 自适应单位:小程序专属适配所有手机
button::after:清除微信按钮默认边框
2.3 首页 index.json
{ "navigationBarTitleText": "幸运抽奖小程序 " }知识点
页面独立配置,优先级高于全局配置,单独设置当前页面导航标题。
2.4 首页 index.wxml 结构代码
<view class="container"> <!-- 装饰图案 --> <view class="decorations"> <view class="decoration cloud"></view> <view class="decoration heart"></view> <view class="decoration star"></view> <view class="decoration star"></view> <view class="decoration star"></view> </view> <!-- 标题 --> <view class="title-box"> <text class="title">🎁 幸运抽奖</text> <text class="subtitle">Lucky Draw</text> </view> <!-- 福袋盲盒 --> <view class="gift-container"> <image src="/images/box.png" class="gift-box {{running ? 'shake' : ''}}" mode="aspectFill"></image> <view class="status">{{running ? '正在抽奖中...' : '点击福袋开启好运'}}</view> </view> <!-- 抽奖次数 --> <view class="count-box"> <text>今日剩余次数:{{count}}</text> </view> <!-- 操作按钮 --> <view class="btn-group"> <button class="btn start" disabled="{{running || count == 0}}" bindtap="start">开始抽奖</button> <button class="btn stop" disabled="{{!running}}" bindtap="stop">停止</button> </view> <!-- 抽奖规则 --> <view class="rule" bindtap="showRule">抽奖规则</view> </view>知识点 & API
数据绑定 {{}}:渲染 js 中的变量数据
三元表达式:动态切换文字、动画 class
bindtap:点击事件绑定 API
disabled:按钮禁用状态动态控制
image 组件:展示本地图片资源
条件动态class:抽奖时自动添加晃动动画
2.5 首页 index.wxss 样式代码
/* 装饰图案 */ .decorations { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; overflow: hidden; } .decoration { position: absolute; opacity: 0.7; animation: float 8s ease-in-out infinite; } .cloud { width: 120rpx; height: 60rpx; background: rgba(255, 255, 255, 0.8); border-radius: 50%; top: 10%; left: 10%; animation-delay: 0s; } .cloud::before, .cloud::after { content: ''; position: absolute; background: rgba(255, 255, 255, 0.8); border-radius: 50%; } .cloud::before { width: 60rpx; height: 60rpx; top: -30rpx; left: 20rpx; } .cloud::after { width: 40rpx; height: 40rpx; top: -20rpx; right: 10rpx; } .heart { width: 40rpx; height: 40rpx; background: #F8BBD0; transform: rotate(45deg); top: 20%; right: 15%; animation-delay: 1s; } .heart::before, .heart::after { content: ''; position: absolute; width: 40rpx; height: 40rpx; background: #F8BBD0; border-radius: 50%; } .heart::before { top: -20rpx; left: 0; } .heart::after { top: 0; left: -20rpx; } .star { width: 0; height: 0; border-left: 20rpx solid transparent; border-right: 20rpx solid transparent; border-bottom: 35rpx solid #B3E5FC; transform: rotate(30deg); top: 30%; left: 20%; animation-delay: 2s; } .star::before { content: ''; position: absolute; width: 0; height: 0; border-left: 20rpx solid transparent; border-right: 20rpx solid transparent; border-bottom: 35rpx solid #B3E5FC; transform: rotate(-70deg); top: -18rpx; left: -20rpx; } @keyframes float { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-20rpx) rotate(5deg); } } /* 标题 */ .title-box{text-align:center;margin-bottom:80rpx;} .title{display:block;font-size:68rpx;font-weight:bold;color:#6A1B9A;text-shadow:0 6rpx 15rpx rgba(106, 27, 154, 0.2);letter-spacing:4rpx;} .subtitle{font-size:28rpx;color:#880E4F;letter-spacing:6rpx;} /* 福袋 */ .gift-container{display:flex;flex-direction:column;align-items:center;margin-bottom:60rpx;} .gift-box{width:340rpx;height:340rpx;border-radius:50rpx;box-shadow:0 25rpx 45rpx rgba(106, 27, 154, 0.2);margin-bottom:30rpx;transition: all 0.3s ease;} .gift-box:hover { transform: translateY(-10rpx); } .shake{animation:shake 0.18s infinite alternate;} @keyframes shake{from{transform:rotate(-6deg);}to{transform:rotate(6deg);}} .status{font-size:32rpx;color:#6A1B9A;} /* 次数 */ .count-box{background:rgba(179, 229, 252, 0.5);padding:16rpx 36rpx;border-radius:50rpx;margin-bottom:50rpx;backdrop-filter: blur(10rpx);} .count-box text{color:#6A1B9A;font-size:28rpx;} /* 按钮组 */ .btn-group{display:flex;gap:35rpx;margin-bottom:40rpx;} .btn{width:240rpx;height:90rpx;font-size:34rpx;border-radius:50rpx;color:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 10rpx 20rpx rgba(0,0,0,0.15);transition: all 0.3s ease;} .btn:hover { transform: translateY(-5rpx); box-shadow: 0 15rpx 25rpx rgba(0,0,0,0.2); } .start{background:linear-gradient(90deg,#92d2e6,#2febf1);color:#6A1B9A;font-weight:bold;} .stop{background:linear-gradient(90deg,#FF8A65,#F4511E);} .btn[disabled]{background:#bbb!important;color:#777!important;box-shadow:none;transform: none;} /* 规则 */ .rule{font-size:24rpx;color:#880E4F;margin-top:10rpx;}知识点
@keyframes 关键帧动画:实现漂浮、晃动效果
clip-path:裁剪星星形状
box-shadow:卡片阴影提升立体感
渐变按钮:蓝粉双色渐变搭配主题
文字阴影 text-shadow:提升文字质感
2.6 首页 index.js 逻辑代码(核心)
Page({ data: { running: false, count: 3, timer: null, prizeIndex: 0 }, start() { if (this.data.running || this.data.count <= 0) return; this.setData({ running: true, count: this.data.count - 1 }); const timer = setInterval(() => { this.setData({ prizeIndex: Math.floor(Math.random() * 8) }); },100); this.setData({timer}) }, stop() { clearInterval(this.data.timer); this.setData({ running: false }); wx.navigateTo({url:`/pages/result/result?index=${this.data.prizeIndex}`}) }, showRule() { wx.showModal({title:'抽奖规则',content:'1.每日免费3次抽奖;2.中奖奖品前往商场服务台兑换;3.活动最终解释权归商场',showCancel:false}) }, onUnload(){clearInterval(this.data.timer)} })核心API & 知识点
Page():注册页面
data:页面数据存储
setData():修改数据、更新视图
setInterval():定时器快速切换奖品模拟抽奖
clearInterval():关闭定时器
Math.random():随机数生成奖品
wx.navigateTo():页面跳转+传参
wx.showModal():弹窗提示API
onUnload:页面卸载生命周期,防止定时器残留
2.7 结果页 result.json
{ "navigationBarTitleText": "抽奖结果" }2.8 结果页 result.wxml
<view class="container"> <!-- 装饰图案 --> <view class="decorations"> <view class="decoration cloud"></view> <view class="decoration heart"></view> <view class="decoration star"></view> </view> <!-- 抽奖结果卡片 --> <view class="result-card"> <image src="/images/{{prize.img}}" class="prize-img" mode="aspectFill"></image> <text class="result-name">{{prize.name}}</text> <text class="result-desc">{{prize.desc}}</text> </view> <!-- 返回按钮 --> <button class="back-btn" bindtap="back">继续抽奖</button> </view>2.9 结果页 result.wxss
/* 装饰图案 */ .decorations { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; overflow: hidden; } .decoration { position: absolute; opacity: 0.7; animation: float 8s ease-in-out infinite; } .cloud { width: 120rpx; height: 60rpx; background: rgba(255, 255, 255, 0.8); border-radius: 50%; top: 10%; left: 10%; animation-delay: 0s; } .cloud::before, .cloud::after { content: ''; position: absolute; background: rgba(255, 255, 255, 0.8); border-radius: 50%; } .cloud::before { width: 60rpx; height: 60rpx; top: -30rpx; left: 20rpx; } .cloud::after { width: 40rpx; height: 40rpx; top: -20rpx; right: 10rpx; } .heart { width: 40rpx; height: 40rpx; background: #F8BBD0; transform: rotate(45deg); top: 20%; right: 15%; animation-delay: 1s; } .heart::before, .heart::after { content: ''; position: absolute; width: 40rpx; height: 40rpx; background: #F8BBD0; border-radius: 50%; } .heart::before { top: -20rpx; left: 0; } .heart::after { top: 0; left: -20rpx; } .star { width: 0; height: 0; border-left: 20rpx solid transparent; border-right: 20rpx solid transparent; border-bottom: 35rpx solid #B3E5FC; transform: rotate(30deg); top: 30%; left: 20%; animation-delay: 2s; } .star::before { content: ''; position: absolute; width: 0; height: 0; border-left: 20rpx solid transparent; border-right: 20rpx solid transparent; border-bottom: 35rpx solid #B3E5FC; transform: rotate(-70deg); top: -18rpx; left: -20rpx; } @keyframes float { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-20rpx) rotate(5deg); } } /* 结果卡片 */ .result-card { background: rgba(255, 255, 255, 0.8); padding: 80rpx 60rpx; border-radius: 40rpx; text-align: center; box-shadow: 0 30rpx 50rpx rgba(106, 27, 154, 0.2); margin-bottom: 70rpx; min-width: 400rpx; backdrop-filter: blur(10rpx); transition: all 0.3s ease; } .result-card:hover { transform: translateY(-10rpx); box-shadow: 0 40rpx 60rpx rgba(106, 27, 154, 0.3); } .prize-img{ width:240rpx; height:240rpx; margin:0 auto 20rpx; border-radius:20rpx; box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.1); } .result-name { font-size: 52rpx; font-weight: bold; color: #6A1B9A; display: block; margin-bottom: 20rpx; } .result-desc { font-size: 30rpx; color: #880E4F; } /* 返回按钮 */ .back-btn { background: linear-gradient(90deg, #b9e7bc, #8af7d6); color: #02529c; font-weight: bold; width: 320rpx; height: 90rpx; border-radius: 50rpx; font-size: 34rpx; display: flex; align-items: center; justify-content: center; box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.15); transition: all 0.3s ease; } .back-btn:hover { transform: translateY(-5rpx); box-shadow: 0 15rpx 25rpx rgba(0,0,0,0.2); }知识点
backdrop-filter: blur:毛玻璃磨砂效果
透明卡片布局:现代化UI设计
延续全局蓝粉渐变主题,界面统一
2.10 结果页 result.js
const prizeArr = [ {img:"p1.png",name:"一等奖",desc:"品牌微波炉一台"}, {img:"p2.png",name:"二等奖",desc:"200元商场实体购物卡"}, {img:"p3.png",name:"三等奖",desc:"50元无门槛代金券"}, {img:"p4.png",name:"参与奖",desc:"高档保温水杯"}, {img:"p5.png",name:"幸运奖",desc:"10元商超现金券"}, {img:"p6.png",name:"纪念奖",desc:"可爱毛绒玩偶"}, {img:"p7.png",name:"购物奖",desc:"30元全场优惠券"}, {img:"p8.png",name:"谢谢参与",desc:"精美小挂件礼品"} ] Page({ data:{prize:{}}, onLoad(options){ let idx = Number(options.index)||7; this.setData({prize:prizeArr[idx]}) }, back(){wx.navigateBack()} })知识点 & API
onLoad(options):页面加载生命周期,接收跳转传参
数组对象存储奖品数据:数据与视图分离
wx.navigateBack():返回上一页API
三、图片资源命名清单(必须严格对应)
将9张图片放入项目images文件夹:
box.png —— 福袋盲盒封面
p1.png —— 一等奖微波炉
p2.png —— 200元购物卡
p3.png —— 50元代金券
p4.png —— 高档保温杯
p5.png —— 10元现金券
p6.png —— 毛绒玩偶
p7.png —— 30元无门槛券
p8.png —— 精美小礼品
四、项目总结
本项目完成了一款高颜值蓝粉色梦幻风微信盲盒抽奖小程序。项目使用微信小程序原生技术开发,实现了页面布局、动态装饰动画、福袋抽奖动画、随机抽奖逻辑、次数限制、页面传参、结果渲染等功能。熟练掌握了小程序数据绑定、事件监听、定时器、页面跳转、CSS动画、Flex布局、毛玻璃效果等核心知识点,界面美观、交互流畅、功能完整,达到小程序前端开发基础实验要求。
