微信小程序之大转盘抽奖原生开发
2021-02-09 本文已影响0人
fingerQin
临近过年了,想在公司的小程序产品上开发一个大转盘抽奖的娱乐功能。应用场景就是给过年的朋友在聚会时抽奖送红包及喝酒时决定谁喝多少杯。
在网上找了好几个案例,不是写得不够详尽。要不就是使用其他第三方开发工具或第三方小程序库来实现。
我的需要很简单,就是想用原生来实现这个功能。这样的好处是可以让小程序主包变得非常的小。不然会超过小程序主包只能 2MB 的限制。需要可能通过分包实现。但是,不想如此麻烦。
一、需求梳理
1)原生开发。避免代码包臃肿。
2)大转盘奖品6个。并且可以动态修改其奖品内容。
3)无须借助服务端 API 接口的数据。
4)点击抽奖按钮要实现音效的播放。
二、技术实现
1)wxml 核心代码如下
<view class="random-dial-area" animation="{{animationData}}">
<image class="random-dial" mode="widthFix" src="/images/random-dial.png"></image>
<block wx:for="{{ awards }}">
<text class="random-dial-name random-dial-name-{{ item.id }}">{{ item.name }}</text>
</block>
</view>
<image class="random-dial-pointer" bindtap="start" src="/images/random-dial-pointer.png"></image>
<view class="random-list">
<van-grid column-num="2" border="{{ false }}">
<block wx:for="{{ awards }}">
<view class="award-item">
<van-grid-item use-slot content-class="award-item-content">{{ item.name }}</van-grid-item>
<van-grid-item use-slot content-class="award-item-content">
<view data-id="{{ item.id }}" bindtap="showEditAwardDialog">修改</view>
</van-grid-item>
</view>
</block>
</van-grid>
</view>
</view>
<van-dialog zIndex="1000" use-slot title="转盘内容修改" show="{{ showDialog }}" show-cancel-button
bind:confirm="onEditAwardName" bind:close="onClose">
<view class="exchange-area">
<van-field value="{{ editName }}" auto-focus="{{ true }}" input-align="center" center="{{ true }}" maxlength="5" placeholder="请输入名称(最多5个字)" border="{{ false }}" bind:change="onChangeEdit" />
</view>
</van-dialog>
view class 等于 random-dial-area 的区域是整个大转盘的区域。它的奖品通过数据绑定展示。这样是为了后续可以动态修改才如此操作。
转盘图片如下:
random-dial.png
转盘的图片我们是留空处理的。所以,并不会在转盘图片上写死。
转盘指针图片如下:
random-dial-pointer.png
我们在指针图片上绑定了一个抽奖的方法:start。点击这个图片大转盘就开会开始旋转。
van-dialog 是我使用了 vant weapp 的弹框组件。因为我们项目里面已经内置了。懒得再去重写一个。大家可以使用自己的弹框组件替换。
2)JS 代码如下
Page({
/**
* 页面的初始数据
*/
data: {
src: '', // 音频播放组件。
deg: 0, // 初始化角度
singleAngle: 60, // 每片扇形的角度
isStart: false,
showDialog: false, // 修改奖项的弹出框是否显示。
editId: 0, // 当前弹框中修改的 ID。
editName: '', // 当前弹框中修改的名称。
animationData: {},
awards: [], // 奖项。
isDefaultAward: false, // 是否默认的奖项。默认显示系统的奖项。如果用户自己设置了则使用用户设置的奖项。
defaultAward: [
{
"id": 1,
"name": "喝一杯"
},
{
"id": 2,
"name": "喝两杯"
},
{
"id": 3,
"name": "喝半杯"
},
{
"id": 4,
"name": "喝一杯"
},
{
"id": 5,
"name": "替人喝"
},
{
"id": 6,
"name": "免喝"
}
]
},
/**
* 检测是否登录。
* -- 未登录跳转到授权界面。
*/
checkLoginStatus() {
const token = wx.getStorageSync('token') ? wx.getStorageSync('token') : '';
if (token.length == 0 || token == undefined) {
wx.navigateTo({
url: '/pages/auth/auth',
})
}
},
/**
* 启动抽奖。
*/
start() {
this.checkLoginStatus();
if (this.data.isStart) {
return;
} else {
this.setData({ isStart: true })
}
/**
* 播放音效。
*/
this.audioCtx = wx.createInnerAudioContext()
this.audioCtx.src = '/packageA/voice/dial.m4a'
this.audioCtx.seek(0.3)
this.audioCtx.play()
let randomVal = Math.random()
let endAddAngle = parseInt(randomVal * 360)
// 为了避免指针指到分隔线上或过于相近的区域没有偏差感。我们要进行角度修饰。
let offsetVal = endAddAngle % 60;
if (offsetVal < 10) {
endAddAngle += 10;
} else if (offsetVal > 50) {
endAddAngle -= 10;
}
const rangeAngle = (Math.floor(Math.random() * 4) + 4) * 360 // 随机旋转几圈再停止
this.animation.rotate(this.data.deg + endAddAngle + rangeAngle).step()
let deg = this.data.deg + rangeAngle
this.setData({ deg: deg, animationData: this.animation.export() })
this.setData({ isStart: false })
},
/**
* 弹框中输入变动事件。
*/
onChangeEdit(event) {
this.setData({ editName: event.detail })
},
/**
* 修改奖项内容。
*/
onEditAwardName(event) {
let awards = this.data.awards
if (this.data.editName.length > 0) {
for (let i in awards) {
if (awards[i].id == this.data.editId) {
awards[i].name = this.data.editName
}
}
}
this.setData({ awards: awards })
},
/**
* 显示修改奖项内容的弹出框。
*/
showEditAwardDialog(event) {
let editId = event.currentTarget.dataset.id;
let editName = ''
for (let i in this.data.awards) {
if (this.data.awards[i].id == editId) {
editName = this.data.awards[i].name
}
}
this.setData({ showDialog: true, editId: editId, editName: editName })
},
/**
* 关联弹出框。
*/
onCloseDialog() {
this.setData({ showDialog: false })
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData({ awards: this.data.defaultAward })
const animation = wx.createAnimation({
duration: 3000,
timingFunction: 'ease-in-out'
})
this.animation = animation
}
})
我们在 onLoad 方法里面创建了动画对象。在 start 里面对这个动画进行了角度计算。实现指针停放的区域。
随后,我们通过调用小程序提供的音频播放接口实现了音效的播放。
3)wxss 样式
这个样式主要是针对大转盘上奖品名称的角度计算。这个确实要花费一些时间。我贴一下我的代码。
.container .random-dial-area {
position: absolute;
width: 683rpx;
height: 683rpx;
top: 323rpx;
left: 36rpx;
}
.container .random-dial {
width: 683rpx;
height: 683rpx;
display: block;
}
.container .random-dial-area .random-dial-name {
position: absolute;
font-size: 31rpx;
width: 170rpx;
text-align: center;
color: #ff302d;
font-weight: 700;
}
.container .random-dial-area .random-dial-name-1 {
transform: rotate(-30deg);
top: 135rpx;
left: 155rpx;
}
.container .random-dial-area .random-dial-name-2 {
transform: rotate(-90deg);
top: 320rpx;
left: 50rpx;
}
.container .random-dial-area .random-dial-name-3 {
transform: rotate(-150deg);
top: 515rpx;
left: 150rpx;
}
.container .random-dial-area .random-dial-name-4 {
transform: rotate(150deg);
top: 515rpx;
left: 365rpx;
}
.container .random-dial-area .random-dial-name-5 {
transform: rotate(90deg);
top: 320rpx;
left: 475rpx;
}
.container .random-dial-area .random-dial-name-6 {
transform: rotate(30deg);
top: 135rpx;
left: 370rpx;
}
因为过于简单。我把代码贴出来。大家跟着操作就一定能得到想要的效果。大家也可以关注微信小程序“娱乐卡”,点击首页的“转轮盘”体验其实际效果。
gh_238f733a1574_344.jpg