当前位置: 首页 > news >正文

【小程序】微信小程序九宫格抽奖动画(完整版)

这是一个微信小程序九宫格抽奖页面的完整代码,包括 WXML、WXSS、JS 和 JSON。

效果

九宫格抽奖

功能说明:

  1. 静态页面布局: 3x3 九宫格,中间是“立即抽奖”按钮,周围是奖品金额。
  2. 抽奖动画: 点击“立即抽奖”后,九宫格会动态跑马灯式高亮显示,最终停留在中奖项。
  3. 中奖提示: 抽奖结束后弹出中奖结果。

1. lottery.json (页面配置)

{"navigationBarTitleText": "九宫格抽奖","usingComponents": {}
}

2. lottery.wxml (页面结构)

<view class="container"><view class="lottery-grid"><block wx:for="{{gridItems}}" wx:key="id"><viewclass="lottery-item {{item.isButton ? 'lottery-btn' : ''}} {{item.active ? 'active' : ''}}"data-index="{{item.id}}"bindtap="{{item.isButton ? 'startLottery' : ''}}"><text>{{item.text}}</text></view></block></view>
</view>

3. lottery.wxss (页面样式)

/* container */
.container {display: flex;justify-content: center;align-items: center;min-height: 100vh; /* 撑满整个屏幕高度 */background-color: #f8f8f8;padding: 20rpx;box-sizing: border-box;
}/* 九宫格容器 */
.lottery-grid {display: grid;grid-template-columns: repeat(3, 1fr); /* 3列,每列等宽 */gap: 15rpx; /* 格子之间的间距 */width: 700rpx; /* 九宫格总宽度 */background-color: #fff;border-radius: 20rpx;padding: 15rpx;box-shadow: 0 5rpx 20rpx rgba(0, 0, 0, 0.1);
}/* 抽奖格子公共样式 */
.lottery-item {width: 100%; /* 充满父容器的宽度 */height: 200rpx; /* 高度 */display: flex;justify-content: center;align-items: center;background-color: #fdfdfd;border: 4rpx solid #ffd700; /* 金色边框 */border-radius: 15rpx;font-size: 36rpx;font-weight: bold;color: #333;transition: all 0.1s ease; /* 动画过渡效果 */box-sizing: border-box; /* 边框和内边距不撑大元素 */
}/* 中间抽奖按钮样式 */
.lottery-btn {background-color: #ffda47; /* 醒目的黄色 */color: #d84e27; /* 红色字体 */font-size: 40rpx;border-color: #f77026; /* 橙色边框 */box-shadow: 0 4rpx 8rpx rgba(255, 165, 0, 0.4);cursor: pointer;
}/* 激活(高亮)状态样式 */
.lottery-item.active {background-color: #ff4d4f; /* 红色高亮 */color: #fff;border-color: #ff0000;transform: scale(1.03); /* 稍微放大 */box-shadow: 0 0 20rpx rgba(255, 77, 79, 0.8);
}/* 按钮禁用状态(抽奖进行中) */
.lottery-btn[disabled] {opacity: 0.7;cursor: not-allowed;background-color: #ccc;border-color: #aaa;
}

4. lottery.js (页面逻辑)

Page({data: {// 九宫格数据// id: 格子索引 (0-8)// text: 显示的文本// isButton: 是否是抽奖按钮 (中间格子)// active: 是否是当前高亮格子gridItems: [],// 抽奖相关状态currentIndex: -1,     // 当前高亮的格子索引isDrawing: false,     // 是否正在抽奖timer: null,          // 抽奖定时器speed: 200,           // 初始转动速度 (ms)minSpeed: 50,         // 最快转动速度 (ms)drawCount: 0,         // 已经转动的次数totalRounds: 3,       // 至少转动多少圈 (影响动画时长)finalPrizeIndex: -1,  // 最终中奖的格子索引accelerateSteps: 10,  // 加速阶段的步数decelerateSteps: 10,  // 减速阶段的步数// 抽奖路径 (按顺时针方向,跳过中间按钮4)// 0 1 2// 7 X 3  (X是中间按钮4)// 6 5 4lotteryPath: [0, 1, 2, 5, 8, 7, 6, 3],},onLoad: function () {this.initGridItems();},/*** 初始化九宫格数据*/initGridItems: function () {const initialGridData = [{ id: 0, text: '5元' },{ id: 1, text: '8元' },{ id: 2, text: '10元' },{ id: 3, text: '90元' }, // 注意这个位置,对应抽奖路径{ id: 4, text: '立即抽奖', isButton: true }, // 中间按钮{ id: 5, text: '20元' }, // 注意这个位置,对应抽奖路径{ id: 6, text: '50元' },{ id: 7, text: '40元' },{ id: 8, text: '30元' }];const gridItems = initialGridData.map(item => ({...item,active: false,isButton: item.isButton || false // 确保 isButton 属性存在}));this.setData({gridItems: gridItems});},/*** 获取下一个高亮的格子索引*/getNextLotteryIndex: function (currentPathIndex) {const { lotteryPath } = this.data;return (currentPathIndex + 1) % lotteryPath.length;},/*** 开始抽奖*/startLottery: function () {if (this.data.isDrawing) {wx.showToast({title: '正在抽奖中...',icon: 'none'});return;}this.setData({isDrawing: true,drawCount: 0,speed: 200, // 恢复初始速度});// 清除上次的定时器,避免重复if (this.data.timer) {clearTimeout(this.data.timer);}// 模拟抽奖结果,这里排除中间按钮(index 4)const prizePoolIndexes = this.data.lotteryPath; // 只有周围的8个格子能中奖const randomIndexInPool = Math.floor(Math.random() * prizePoolIndexes.length);const finalPrizeIndex = prizePoolIndexes[randomIndexInPool];console.log("最终中奖格子索引 (在 lotteryPath 中的位置):", randomIndexInPool);console.log("最终中奖格子在 gridItems 中的实际ID:", finalPrizeIndex);this.setData({finalPrizeIndex: finalPrizeIndex,currentIndex: this.data.lotteryPath[0] // 初始从第一个格子开始}, () => {// 确保 finalPrizeIndex 设置后再启动动画this.runLottery();});},/*** 运行抽奖动画*/runLottery: function () {let { gridItems, currentIndex, drawCount, speed, minSpeed,finalPrizeIndex, lotteryPath, totalRounds, accelerateSteps, decelerateSteps } = this.data;// 清除上一个高亮if (currentIndex !== -1) {let oldGridItems = gridItems;const oldIndexInPath = lotteryPath.indexOf(currentIndex);oldGridItems[lotteryPath[oldIndexInPath]].active = false;this.setData({ gridItems: oldGridItems });}// 计算下一个高亮索引const currentPathIndex = lotteryPath.indexOf(currentIndex);const nextPathIndex = this.getNextLotteryIndex(currentPathIndex);const nextActualIndex = lotteryPath[nextPathIndex];// 更新高亮gridItems[nextActualIndex].active = true;this.setData({gridItems: gridItems,currentIndex: nextActualIndex,drawCount: drawCount + 1});// 计算总的转动步数,确保至少转totalRounds圈 + 停到中奖位置// 假设 finalPrizeIndex 是在 lotteryPath 中的实际索引const prizePathIndex = lotteryPath.indexOf(finalPrizeIndex);const minRunSteps = lotteryPath.length * totalRounds + prizePathIndex + 1; // 至少转的步数// 速度控制let newSpeed = speed;if (drawCount < accelerateSteps) { // 加速阶段newSpeed = Math.max(minSpeed, speed - (speed - minSpeed) / accelerateSteps * drawCount);} else if (drawCount >= minRunSteps - decelerateSteps && drawCount < minRunSteps) { // 减速阶段newSpeed = Math.min(200, speed + (200 - minSpeed) / decelerateSteps);} else if (drawCount >= minRunSteps) { // 减速到最终结果,确保最终速度不会太快newSpeed = Math.min(newSpeed + 30, 400); // 逐渐变慢}// 检查是否停止const isStop = drawCount >= minRunSteps && currentIndex === finalPrizeIndex;if (isStop) {clearTimeout(this.data.timer);this.setData({isDrawing: false,timer: null});wx.showModal({title: '恭喜!',content: '您抽中了' + gridItems[finalPrizeIndex].text + '!',showCancel: false,confirmText: '确定'});} else {this.setData({ speed: newSpeed });this.data.timer = setTimeout(() => this.runLottery(), newSpeed);}},onUnload: function() {// 页面卸载时清除定时器,避免内存泄漏if (this.data.timer) {clearTimeout(this.data.timer);this.setData({ timer: null });}}
});

文章转载自:

http://ygi4sekl.xnwjt.cn
http://S66EyEo9.xnwjt.cn
http://YIlR3nKo.xnwjt.cn
http://CBvkCELt.xnwjt.cn
http://dy5uGqip.xnwjt.cn
http://pnhT156U.xnwjt.cn
http://bfWG6REW.xnwjt.cn
http://eNVBd7bi.xnwjt.cn
http://Tzpuc78X.xnwjt.cn
http://XW0Rx7nd.xnwjt.cn
http://6LaTZtkg.xnwjt.cn
http://a303X2zW.xnwjt.cn
http://Fky4v2do.xnwjt.cn
http://Vj4k8M2D.xnwjt.cn
http://EsNh1h3h.xnwjt.cn
http://yRTJsSu2.xnwjt.cn
http://hZuwGzgy.xnwjt.cn
http://NPZwmn4w.xnwjt.cn
http://mRgbPFu9.xnwjt.cn
http://hLefzyN3.xnwjt.cn
http://k8JxTvHH.xnwjt.cn
http://h6iysRWy.xnwjt.cn
http://pBvJy9jw.xnwjt.cn
http://TyND1AuT.xnwjt.cn
http://bqbIxfKi.xnwjt.cn
http://2A7cv5dp.xnwjt.cn
http://fg7GnlIx.xnwjt.cn
http://Uwxy3Ysf.xnwjt.cn
http://zi0sA3UR.xnwjt.cn
http://Y3IdFITH.xnwjt.cn
http://www.dtcms.com/a/380357.html

相关文章:

  • [BJDCTF 2020]encode
  • 系统核心解析:深入操作系统内部机制——进程管理与控制指南(一)【进程/PCB】
  • 速通ACM省铜第二天 赋源码(Adjacent XOR和Arboris Contractio)
  • Python快速入门专业版(二十四):while循环:条件循环与“死循环”避免(猜数字游戏案例)
  • 神经网络构成框架-理论学习
  • 智能眼镜产品成熟度分析框架与评估
  • 从零学算法2327
  • 【C++】:list容器全面解析
  • 渲染农场多少钱一小时
  • IDEA试用过期,无法登录,重置方法
  • IP验证学习之case编写
  • 通过Dockerfile构建Docker镜像并训练模型
  • 操作系统内核架构深度解析:从微内核到宏内核的设计哲学与性能权衡
  • IIS运行账户设置记录
  • 服务管理 systemctl
  • HTTP与HTTPS
  • devextreme-vue表格设置可复制粘贴
  • Go 语言 PDF 生成库综合比较与实践指南
  • 图技术重塑金融未来:悦数图数据库如何驱动行业创新与风控变革
  • 金融数据---ETF日线行情数据
  • Vue 整体框架全面解析
  • 鸿蒙 NEXT应用国际化:时区与夏令时处理
  • 海外代理IP平台哪家好?高纯净度稳定住宅代理IP平台推荐
  • 锂电池行业生产中 AI 应用场景与价值分析
  • MySQL 命令行导入 SQL 文件
  • 3DMAX自动材质开关插件AutoMaterial安装和使用方法
  • Ubuntu C编程 (make工具和Makefile的引用)
  • 9.12AI简报丨腾讯投资AI游戏平台,B站开源AniSora V3
  • 家庭健康智能终端:解锁智能家居时代的健康管理
  • 机器视觉检测如何使用360 度全景成像镜头进行AI 瑕疵检测