支付宝 小程序 抽奖组件 大转盘

news2024/10/7 10:13:27

介绍

使用支付宝原有的大转盘营销组件进行改造的,由于背景使用的图片,目前只支持 6 个奖品,一般情况下的大转盘都是这个规格。
转盘停止:之前使用的是计算角度来完成的,没有那种缓慢停止的动画。现在加了一个缓慢停止的动画,让抽奖变得更加顺滑
录出来的动图可能会看到转盘往相反方向转动,但是真机的视觉效果上是看不出来的。

转盘效果图

在这里插入图片描述
在这里插入图片描述

页面代码

index.axml

<view class="lucky-draw-wrapper">
  <view class="chance-logs-container">
    <view class="remaining-chance">
      您有
      <text class="chance">{{ chance }}</text>
      次抽奖机会
    </view>
  </view>
  <turntable
    prizeList="{{ prizeList }}"
    rotTimes="{{ chance }}"
    onStart="onStart"
    onFinish="onFinish"
    onTimesUp="onTimesUp"
  />
</view>

index.js

Page({
  data: {
    prizeList: [
      {
        prizeId: '646739d6dcca4d1f505cb0d3',
        name: 'H&M100元优惠券',
        type: 'COUPON',
        image: 'https://gw.alipayobjects.com/zos/rmsportal/nIQUKeYBbJWliGJVhVmx.png',
      },
      {
        prizeId: '646739d6dcca4d1f505cb0d4',
        name: '2元话费券',
        type: 'COUPON',
        image: 'https://gw.alipayobjects.com/zos/rmsportal/HkrVjjjuxZPUMCUbPazb.png',
      },
      {
        prizeId: '646739d6dcca4d1f505cb0d5',
        name: '45元飞猪出行券',
        type: 'COUPON',
        image: 'https://gw.alipayobjects.com/zos/rmsportal/cDctUxwBLPCszQHRapYV.png',
      },
      {
        prizeId: '646739d6dcca4d1f505cb0d6',
        name: 'H&M10元优惠券',
        type: 'COUPON',
        image: 'https://gw.alipayobjects.com/zos/rmsportal/FAmIWZAWpUwlRFKqQDLz.png',
      },
      {
        prizeId: '646739d6dcca4d1f505cb0d7',
        name: '2元流量券',
        type: 'COUPON',
        image: 'https://gw.alipayobjects.com/zos/rmsportal/cuGomeXzMyeeZMjvVjBj.png',
      },
      {
        prizeId: '646739d6dcca4d1f505cb0d8',
        name: '谢谢参与',
        type: 'NONE',
        image: 'https://zos.alipayobjects.com/rmsportal/dwhgPyWAcXuvJAWlSSgU.png',
      },
    ],
    chance: 3,
  },
  onLoad() {
  },
  async onStart() {
    return this.data.prizeList[Math.floor(Math.random() * 6)];
  },
  async onFinish(result) {
    if (!result) {
      return;
    }

    const { type, name } = result;
    my.showToast({
      type: 'none',
      content: type === 'NONE' ? '很遗憾,差点就中奖了' : `恭喜您,获得${name}`,
    });
    this.setData({
      chance: this.data.chance - 1,
    });
  },
  onTimesUp() {
    my.showToast({
      type: 'none',
      content: '您的抽奖次数已用完',
    });
  },
});

index.json

{
  "transparentTitle": "auto",
  "titlePenetrate":"YES",
  "barButtonTheme": "default",
  "usingComponents": {
    "turntable": "./components/Turntable/index"
  }
}

turntable 组件代码

index.axml

<view class="turntable-container" style="width:{{ width }}rpx; height:{{ width }}rpx;">
  <view
    class="turntable-list {{ animationStatus }}"
    style="background:url('{{ bgImg }}') 0% 0% / 100% 100% no-repeat; {{ transform }}"
  >
    <view a:for="{{ prizeList }}" a:for-index="i">
      <view class="turntable-item">
        <view
          class="turntable-img"
          style="width:{{ prizeWidth }}; padding-top:{{ prizePaddingTop }}; transform:rotate({{ (i + 0.5) / 6 }}turn);{{ itemTransformOrigin }}"
        >
          <view class="prize-name {{ item.type === 'NONE' ? 'none' : '' }}">{{ item.name }}</view>
          <view a:if="{{ item.coupon }}" class="desc">{{ item.coupon.shortDesc }}</view>
          <image src="{{ item.image }}" mode="widthFix" class="prize-img" />
        </view>
      </view>
    </view>
  </view>
  <view class="turntable-btn" >
    <image src="{{ btnImg }}" mode="widthFix" class="img" onTap="onDraw" />
  </view>
</view>

index.acss

.turntable-container {
  position: relative;
  margin: auto;
  border-radius: 50%;
  overflow: hidden;
}

.turntable-list {
  position: absolute;
  border-radius: 50%;
  width: inherit;
  height: inherit;
  transition: all 6s ease;
  -webkit-transition: all 6s ease;
}

.turntable-list.scrolling {
  animation: scroll-start 0.4s linear infinite;
}

@keyframes scroll-start {
  from {
    transform: rotate(0);
  }

  to {
    transform: rotate(360deg);
  }
}

.turntable-list.stop {
  animation: scroll-slow-down 0.7s ease-out;
}

@keyframes scroll-slow-down {
  from {
    transform: rotate(0);
  }

  to {
    transform: rotate(360deg);
  }
}

.turntable-list.stop-win {
  animation: scroll-slow-down-win 0.7s ease-out;
}

@keyframes scroll-slow-down-win {
  from {
    transform: rotate(0);
  }

  to {
    transform: rotate(330deg);
  }
}

.turntable-item {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

.turntable-img {
  position: relative;
  display: block;
  margin: 0 auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.turntable-img .prize-name {
  width: 200rpx;
  padding: 30rpx 0 20rpx;
  color: #000;
  font-weight: 600;
  font-size: 32rpx;
  line-height: 30rpx;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.turntable-img .prize-name.none {
  color: rgba(17, 17, 17, 0.55);
}

.turntable-img .desc {
  margin-top: -10rpx;
  font-size: 20rpx;
  line-height: 28rpx;
  color: rgba(0, 0, 0, 0.65);
}

.turntable-img .prize-img {
  display: block;
  max-width: 120rpx;
  height: 85rpx;
}

.turntable-btn {
  position: absolute;
  top: -12rpx;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.turntable-btn .img {
  width: 20%;
}

index.js

Component({
  data: {
    degValue: 0, // 旋转角度
    prizeWidth: 0, // 奖项背景图宽度计算值
    prizePaddingTop: 0, // 奖项上边距计算值
    itemTransformOrigin: '', // 奖项旋转原点计算值
    animationStatus: '',
    transform: '',
  },
  props: {
    width: 690, // 画布大小,默认单位 rpx
    initDeg: 0, // 初始旋转角度
    rotTimes: 0, // 抽奖机会次数
    prizeList: [], // 奖品列表
    prizeWidth: NaN, // 奖项宽度
    prizePaddingTop: NaN, // 奖项距离圆弧的内边距
    bgImg: 'https://gw.alipayobjects.com/zos/rmsportal/YIunNQVWkFRxUTaUNhOZ.png', // 背景图
    btnImg: 'https://gw.alipayobjects.com/zos/rmsportal/JHenAywYHZTLbbrnkIFN.png', // 按钮图
    onStart() {}, // 开始回调
    onFinish() {}, // 结束回调
    onTimesUp() {}, // 次数用尽的回调
  },
  didMount() {
    const widthNum = this._getNum(this.props.width);
    const widthUnit = this._getUnit(this.props.width);
    const { prizeWidth } = this.props;
    const paddingTop = this.props.prizePaddingTop;
    this.setData({
      degValue: this.props.initDeg,
      itemTransformOrigin: `transform-origin: 50% ${0.5 * widthNum}${widthUnit};`,
      prizeWidth: isNaN(prizeWidth) ? this._calculatePrizeWidth() : prizeWidth,
      prizePaddingTop: isNaN(paddingTop) ? this._calculatePrizePaddingTop() : paddingTop,
    });
    this.count = 6; // 奖品个数
    this.rotNum = 0; // 当前是第几次抽奖
    this.onRunning = false; // 是否正在抽奖
  },
  methods: {
    async onDraw() {
      if (this.onRunning) {
        return;
      }

      if (this.props.rotTimes < 1) {
        this.props.onTimesUp();
        return;
      }

      this.onRunning = true;
      this.setData({ animationStatus: 'scrolling' });
      const result = await this.props.onStart();
      // 延迟2秒钟展示奖品
      setTimeout(() => {
        this.done(result);
      }, 2000);
    },
    done(result) {
      if (!result) {
        this.onRunning = false;
        this.props.onFinish(null);
        this.setData({ animationStatus: 'stop', transform: '' });
        return;
      }

      this.setData({ animationStatus: 'stop-win', transform: 'transform: rotate(-30deg);' });
      let tempData = this.props.prizeList;
      for (let index = 0; index < tempData.length; index++) {
        if (tempData[index].prizeId === result.prizeId) {
          const itemAfterIndex = tempData.slice(index, this.props.prizeList.length);
          const itemBeforeIndex = tempData.slice(0, index);
          tempData = itemAfterIndex.concat(...itemBeforeIndex);
        }
      }
      this.setData({
        prizeList: tempData,
      });
      // 转盘停止1秒钟后展示弹框
      setTimeout(() => {
        this.onRunning = false;
        this.props.onFinish(result);
      }, 1000);
    },
    _getNum(str) {
      // 获取像素选项数值
      return parseFloat(str);
    },
    _getUnit(str) {
      // 获取像素选项单位
      // eslint-disable-next-line no-param-reassign
      str += '';
      return (str.match(/[a-z]+$/) || [])[0] || 'rpx';
    },
    _calculatePrizeWidth() {
      // 等边三角形内接正方形边长: (4 - 2 * 根号3) * 边长
      const widthNum = this._getNum(this.props.width);
      const widthUnit = this._getUnit(this.props.width);
      return (4 - 2 * Math.sqrt(3)) * 0.5 * widthNum + widthUnit;
    },
    _calculatePrizePaddingTop() {
      // 等边三角形一边的中点离过该边两点的圆弧的距离: 边长 - 边长 * (根号3 / 2)
      const widthNum = this._getNum(this.props.width);
      const widthUnit = this._getUnit(this.props.width);
      return 0.5 * widthNum - 0.25 * widthNum * Math.sqrt(3) + widthUnit;
    },
  },
});

index.json

{
  "component": true
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/588866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android实现皮肤主题修改

最近在做App内皮肤切换功能&#xff0c;想了很久方案&#xff0c;写了个皮肤更换工具类&#xff0c;适配N皮肤种类。 话不多说&#xff0c;直接捋一下我的设计思路&#xff0c;因为我的App默认为黑色主题&#xff0c;因此在做其他皮肤主题时&#xff0c;我的图片命名方式是直接…

Fastjson核心解析器DefaultJSONParser,解析算法递归下降算法,实例解析json的步骤

先恭喜热火没有在3-0的情况下被凯尔特人翻盘&#xff0c;抢七获胜成功晋级总决赛~ 最近的项目用到了fastjson&#xff0c;因为源码比较容易搞到&#xff0c;所以就拿来简单的了解了一下&#xff0c;json的主要功能就是解析json和生成json字符串&#xff0c;今天主要是从解析jso…

基于vue3.0简单的页面使用

基于vue3.0简单的页面使用 项目效果图项目文件图package.jsonmain.jsApp.vueviews/Tutorial.vueviews/TS.vueviews/Docs.vueviews/Community.vueviews/Blog.vueviews/About.vueutils/create.jsxutils/defineCom.jsutils/DragIcon.jsutils/someName.tsutils/TS.tsstores/client.…

win11任务栏时间改成12时制

需求&#xff1a;默认24小时值&#xff0c;想改成12小时3:49 方法&#xff1a;设置-时间和语言-语言和区域-管理语言设置-格式 将时间格式改成带tt的

2022年长三角高校数学建模竞赛C题隧道的升级改造与设计解题全过程文档及程序

2022年长三角高校数学建模竞赛 C题 隧道的升级改造与设计 原题再现&#xff1a; 某地现存一旧式双洞隧道&#xff0c;现计划将该隧道在旧貌基础上升级改造。在升级改造前&#xff0c;需进行定标与设计。考虑到该隧道洞壁附着特殊涂料&#xff0c;无人机在洞内通信信号较差&am…

网络面试题:什么是 TCP/IP?

目录标题 什么是 TCP/IP?1) 网络接口层:2) 网络层:3) 传输层:4) 应用层: 2.数据包3.网络接口层4.网络层1) IP:2)地址解析协议 ARP3)子网 5 传输层1&#xff09;UDP&#xff1a;2&#xff09;TCP&#xff1a; 6 应用层运行在TCP协议上的协议&#xff1a;运行在UDP协议上的协议&…

Netty 实现百万级连接服务的难点和优点分析总结

推送服务 还记得一年半前&#xff0c;做的一个项目需要用到 Android 推送服务。和 iOS 不同&#xff0c;Android 生态中没有统一的推送服务。Google 虽然有 Google Cloud Messaging &#xff0c;但是连国外都没统一&#xff0c;更别说国内了&#xff0c;直接被墙。 所以之前在…

Lua学习笔记:C/C++和Lua的相互调用

前言 本篇在讲什么 C/C和Lua的相互调用 本篇适合什么 适合初学Lua的小白 适合需要C/C和lua结合开发的人 本篇需要什么 对Lua语法有简单认知 对C/C语法有简单认知 依赖Lua5.1的环境 依赖VS 2017编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&…

云南智慧档案库综合管理系统建设解决方案

一、智慧档案管理系统建设背景 档案作为一种特殊的文献&#xff0c;是人类社会活动的产物&#xff0c;具有特殊的价值&#xff0c;其价值可以概括为现实价值和历史价值。档案是人类留给国家和社会的宝贵财富&#xff0c;它在经济与社会建设中起着重要的作用。档案是反映一个单…

多重共线性的处理方法

回归分析需要考虑多重共线性问题。多重共线性是指自变量之间存在高度相关性&#xff0c;导致回归模型的系数估计不稳定和假设检验不可靠。在实际应用中&#xff0c;许多自变量之间都可能存在一定程度的相关性&#xff0c;如果没有进行控制&#xff0c;就会导致多重共线性问题的…

设计模式之美-实战二:如何对接口鉴权这样一个功能开发做面向对象分析?

面向对象的三个环节&#xff1a;面向对象分析&#xff08;OOA&#xff09;、面向对象设计&#xff08;OOD&#xff09;、面向对象编程&#xff08;OOP&#xff09;。只知道OOA、OOD、OOP只能说有一个宏观了解&#xff0c;我们更重要的还是要知道“如何做”&#xff0c;也就是&a…

【快应用】多语言适配案例

【关键词】 多语言&#xff0c;$t 【问题背景】 快应用平台的能力会覆盖多个国家地区&#xff0c;平台支持多语言的能力后&#xff0c;可以让一个快应同时支持多个语言版本的切换&#xff0c;开发者无需开发多个不同语言的源码项目&#xff0c;避免给项目维护带来困难。使用系…

子串分值--子串分值和 模拟,找规律

子串分值和 n有十万&#xff0c;需要找规律&#xff0c;O(n^2)不满足要求 分析样例&#xff1a; Ababc 01234 长度是n5 索引下标-对应字符 0A贡献 112 a;ab;---22*1 next a 2&#xff1b; pre a -1 1b贡献 112 b;ba;---42*2 next b 3&#xff1b; pre b -1 2a贡献 1113…

2023年测试前景?测试开发工程师养成记,开发企业级测试平台...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试开发&#xff…

IDS 和 IPS 日志监控

什么是IDS/IPS 入侵检测系统 &#xff08;IDS&#xff09; 和入侵防御系统 &#xff08;IPS&#xff09; 是监视组织网络中的流量以检测和防止恶意活动和策略违规的网络组件。 入侵检测系统&#xff08;IDS&#xff09;和入侵防御系统&#xff08;IPS&#xff09;可以说是企业…

C语言学习分享(第八次)------数据的存储

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 数据的存储 1. 前言&#x1f6a9;2…

现代化智慧档案室建设图文推介

1、防火。建立档案库房防火制度&#xff0c;档案库房附近严禁存放易燃、易爆物品&#xff0c;库房内严禁吸烟&#xff0c;并备有灭火器&#xff0c;经常进行检查更换。 主要设备为&#xff1a;烟雾探测器和感温探测器和七氟丙烷灭火系统。 2、防潮。库房内备有温湿度计&#x…

GB28181 对接海康平台,解决音视频卡顿问题

GB28181 对接海康平台,解决音视频卡顿问题 一、概述二、问题分析1、设备对比分析2、抓包对比分析3、验证分析结果三、总结四、讨论一、概述 设备使用GB28181协议对接海康平台时,发现音频和视频存在卡顿现象,不是一直卡顿,有时候卡有时候不卡,但是卡顿的时候音视频一起卡顿…

炫技操作--递归实现翻转链表(java)

递归实现链表的逆序 leetcode 206题。 翻转链表递归解法普通方式实现链表翻转链表专题 leetcode 206题。 翻转链表 leetcode链接用于测试 题目&#xff1a;描述 将一个链表翻转&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 递归解法 解题思路…

chatgpt赋能python:Python中删除的SEO

Python中删除的SEO Python是一个强大的编程语言&#xff0c;它广泛应用于各种领域&#xff0c;包括SEO。在SEO领域中&#xff0c;Python可以用来处理各种数据&#xff0c;包括删除不必要的数据。本文将介绍如何在Python中删除SEO数据。 什么是SEO数据&#xff1f; SEO是搜索…