上代码:
axml
<view class="fruit-slots ">
<view class="title">今日还剩{{isDrawVO.remainingCount||0}}次抽奖机会</view>
<view class="lt-item-list">
<block a:for="{{prizeBox}}">
<view key="{{index}}" class="lt-item {{index === activeIndex ? 'lt-active' : ''}}">
<image src="{{item.icon}}" mode="widthFix" style="width:100%;height:100%;" />
</view>
<!-- <view key="btn" a:if="{{index==3}}" class="lt-item lt-button {{disabled ? 'disabled' : (isRolling ? 'pause' : '')}}"
onTap="startClick" /> -->
<view key="btn" a:if="{{index==3}}" class="lt-item {{disabled ? 'disabled' : (isRolling ? 'pause' : '')}}"
style="background:url('{{drawBtnImg}}') no-repeat center / cover"
onTap="startClick" />
</block>
</view>
</view>
acss
.lt-item-list {
margin: 20rpx auto;
background: url("https://xiaojinhe-cdn.iyoudui.com/activity/lottert-bg.png")
no-repeat center / 100%;
width: 702rpx;
height: 576rpx;
padding: 20rpx;
padding-top: 80rpx;
border-radius: 20rpx;
box-sizing: border-box;
/* border: 1rpx solid red; */
}
.fruit-slots {
/* border: 1rpx solid green; */
position: relative;
}
.title {
position: absolute;
top: 17rpx;
left: 50%;
transform: translateX(-50%);
font-weight: 700;
font-size: 28rpx;
line-height: 42rpx;
color: #fff;
}
.lt-item {
margin: 16rpx 0 0 16rpx;
width: 210rpx;
height: 145rpx;
padding: 0;
float: left;
display: inline-block;
background-repeat: no-repeat;
background-position: left top;
box-sizing: border-box;
border-radius: 20rpx;
background-color: #eff1dd;
overflow: hidden;
}
/* .lt-item:nth-child(1) {
background-color: #c3ebfa;
}
.lt-item:nth-child(2) {
background-color: #eff1dd;
}
.lt-item:nth-child(3) {
background-color: #f1d6dc;
}
.lt-item:nth-child(4) {
background-color: #f1d6dc;
} */
.lt-item:nth-child(5) {
background-color: #2683fc;
border: none;
}
/* .lt-item:nth-child(6) {
background-color: #c3ebfa;
}
.lt-item:nth-child(7) {
background-color: #eff1dd;
}
.lt-item:nth-child(8) {
background-color: #c3ebfa;
}
.lt-item:nth-child(9) {
background-color: #f1d6dc;
} */
.lt-item:nth-child(1),
.lt-item:nth-child(4),
.lt-item:nth-child(7) {
margin-left: 0 !important;
}
.lt-item:nth-child(1),
.lt-item:nth-child(2),
.lt-item:nth-child(3) {
margin-top: 0 !important;
}
.lt-active {
background-repeat: no-repeat;
background-position: left top;
box-sizing: border-box;
/* filter: contrast(50%); */
filter: brightness(50%);
}
.lt-button {
background-repeat: no-repeat;
background-size: contain;
background-image: url(https://zos.alipayobjects.com/rmsportal/CNzFiofsxZsEPuzbORIA.png);
}
.lt-button.disabled {
background-image: url(https://zos.alipayobjects.com/rmsportal/JbBzEiibIXRGxXPRzJIg.png);
}
.lt-button.pause {
background-image: url(https://zos.alipayobjects.com/rmsportal/eGLmgGZHTDBjtzwhxNkJ.png);
}
js
Component({
data: {
activeOrder: [0, 1, 2, 4, 7, 6, 5, 3], // 九宫格除按钮外的8个格子自左上角顺时针的下标顺序
activeIndex: NaN,
itemWidth: 0,
isRolling: false,
},
props: {
width: 700, // 组件宽度,单位 rpx
margin: 20, // 奖项之间的外边距,单位 rpx
prizeBox: [], // 奖项列表,个数限定为8
prizeName: "", // 获奖项名称
rollTimes: 3, // 转动圈数
mode: "pre", // 抽奖模式:pre(默认) | realtime
currentIndex: 0, // 转动开始的下标
speed: 100, // 转动速度, 单位 ms
isDrawVO: {},
drawBtnImg: "",
disabled: false, // 按钮是否可点击
onStart: function onStart() {}, // 开始的回调
onFinish: function onFinish() {}, // 结束的回调
onClickDraw: () => {},
},
didMount: function didMount() {
this.prizeLength = 8;
// 必须要取整,否则部分机型下有适配问题
this.setData({
itemWidth: parseInt((this.props.width - 4 * this.props.margin) / 3),
});
},
didUpdate: function didUpdate(prevProps) {
var _props = this.props,
mode = _props.mode,
prizeName = _props.prizeName;
if (mode === "realtime" && prizeName && prevProps.prizeName !== prizeName) {
var prizeIndex = this.findPrizeIndex(prizeName);
if (prizeIndex === -1) {
console.error(
"请传入正确的获奖项name,其值必须存在于 prizeBox name 字段中"
);
return;
}
// 总转动步数 = 默认圈数 x 奖品个数 + 结束位置索引 + 当前位置到一圈结束还剩下的步数
var activeIndex = this.currentStep % this.prizeLength;
this.totalSteps =
1 * this.prizeLength +
this.currentStep +
(this.prizeLength - activeIndex) +
prizeIndex;
}
},
methods: {
next: function next(activeIndex) {
var _this = this;
activeIndex = activeIndex % this.prizeLength;
this.setData({ activeIndex: this.data.activeOrder[activeIndex] });
if (this.currentStep === this.totalSteps) {
this.done(activeIndex);
return;
}
this.currentStep += 1;
setTimeout(function () {
_this.next(++activeIndex);
}, this.speedCtl());
},
/**
模拟速度变化,分为四档
当走过格子数 < 总步数 - 2圈格子数时,速度为speed
以此线性递增
*/
speedCtl: function speedCtl() {
var steps = this.totalSteps;
var size = this.prizeLength;
var currentStep = this.currentStep;
if (currentStep < steps - size * 2) {
return this.props.speed;
} else if (
steps - size * 2 <= currentStep &&
currentStep <= steps - size
) {
return this.props.speed * 2;
} else if (steps - currentStep > 3) {
return this.props.speed * 3;
} else {
return this.props.speed * 4;
}
},
/**
通过名称获取奖品项在顺时针格子中对应的下标
未找到返回-1
*/
findPrizeIndex: function findPrizeIndex(name) {
var prizeBox = this.props.prizeBox;
var order = this.data.activeOrder;
for (var i = 0; i < this.prizeLength; i++) {
if (prizeBox[order[i]].name == name) {
return i;
}
}
return -1;
},
startClick() {
if (this.props.disabled || this.data.isRolling) return;
this.props.onClickDraw();
},
start: function start(position) {
var _props2 = this.props,
disabled = _props2.disabled,
prizeBox = _props2.prizeBox,
currentIndex = _props2.currentIndex,
prizeName = _props2.prizeName,
mode = _props2.mode;
if (disabled || this.data.isRolling) return;
this.currentStep = 0;
if (prizeBox.length !== 8) {
console.error("奖品项列表 prizeBox 长度不为8");
}
var activeIndex = +currentIndex || 0;
if (mode === "realtime") {
this.totalSteps = Infinity;
} else {
// 奖品项下标
var prizeIndex = this.findPrizeIndex(prizeName);
if (prizeIndex === -1) {
console.error(
"请传入正确的获奖项name,其值必须存在于 prizeBox name 字段中"
);
}
// 总转动步数 = 默认圈数 x 奖品个数 + 结束位置索引 + 当前位置到一圈结束还剩下的步数
this.totalSteps =
this.props.rollTimes * this.prizeLength +
prizeIndex +
(this.prizeLength - activeIndex);
}
this.setData({ isRolling: true });
this.next(activeIndex);
this.props.onStart(position);
},
done: function done(activeIndex) {
var _this2 = this;
// setTimeout防止抽奖结束后父组件设置disabled=true的过程中用户马上再次点击抽奖 此时 disabled 和 isRolling
// 状态还没来得及更新,start 函数可能被执行
setTimeout(function () {
_this2.setData({ isRolling: false });
}, 50);
this.props.onFinish(activeIndex, this.props.prizeName);
// 中奖后清除遮罩
setTimeout(() => {
this.setData({ activeIndex: NaN });
}, 1000);
},
},
});
html使用
<fruit-slots
ref="fruitRef"
mode="realtime"
prizeBox="{{prizeBox}}"
prizeName="{{prizeName}}"
disabled="{{disabled}}"
isDrawVO="{{isDrawVO}}"
drawBtnImg="{{drawBtnImg}}"
rollTimes="3"
onClickDraw="onClickDraw"
onStart="onStart"
onFinish="onFinish"
speed="50"
/>