目录
- 需求背景
- 需求实现
- 实现过程图片示意
- 实现代码
- 页面效果
- lucky-canvas 插件官方文档
需求背景
要求实现转盘转动抽奖的功能:
- 只有正确率大于等于 80% 才可以进行抽奖;
- “谢谢参与”概率为 90%,“恭喜中奖”概率为 10%;
需求实现
实现过程图片示意
实现代码
安装插件
npm install @lucky-canvas/vue@latest
main.js 全局引入组件
import VueLuckyCanvas from '@lucky-canvas/vue'
Vue.use(VueLuckyCanvas)
实现代码
<template>
<div class="exam-result">
<div class="info">
<div class="progress">
<nut-circleprogress
:progress="(correct / total).toFixed(1) * 100"
:is-auto="true"
color="#ff4d4f"
path-color="#ffeded"
>
<div class="progressDiv">
<div class="accuracy">正确率{{ (correct / total).toFixed(1) * 100 }}%</div>
</div>
</nut-circleprogress>
</div>
</div>
<div class="content">
<div class="result-table">
<div style="padding: 10px 10px 10px 15px">试卷分析</div>
</div>
<div class="result-table">
<div class="item">
<div class="title">题目总量:</div>
<div class="total">{{ total }}</div>
<div class="unit">题</div>
</div>
</div>
<div class="result-table">
<div class="item">
<div class="title">正确题数:</div>
<div class="correct">{{ correct }}</div>
<div class="unit">题</div>
</div>
<div class="item">
<div class="title">错误题数:</div>
<div class="error">{{ total - correct }}
</div>
<div class="unit">题</div>
</div>
</div>
</div>
<div v-if="examType === 'challenge' && (correct / total).toFixed(1) >= 0.8" class="lottery_draw_btn">恭喜您获得抽奖资格 <nut-button type="primary" size="mini" @click="toLotteryDraw">点击进行抽奖</nut-button></div>
<nut-dialog teleport="#app" :title="isShowlotteryDraw ? '点击“开始”抽奖' : ''" content="" v-model:visible="dialogVisible" customClass="task" :noCancelBtn="true" :noOkBtn="true" :closeOnClickOverlay="false">
<nut-icon name="close" @click="dialogVisible = false" />
<LuckyWheel
v-if="isShowlotteryDraw"
class="myLucky"
ref="myLuckyRef"
width="320px"
height="320px"
:prizes="prizes"
:blocks="blocks"
:buttons="buttons"
@start="startCallback"
@end="endCallback"
/>
<div v-else class="result" :style="{'--color': lotteryDrawIndex === 1 ? 'red' : '#000'}">{{ lotteryDrawIndex === 1 ? "恭喜中奖" : "谢谢参与" }}</div>
</nut-dialog>
</div>
<fallback></fallback>
</template>
<script>
import {
reactive, toRefs, ref, getCurrentInstance
} from 'vue'
import { useRoute } from 'vue-router'
export default {
name: 'result',
setup() {
// const myLuckyRef = ref(null) // 【ref问题】我的代码里这种办法取不到 ref,使用 getCurrentInstance 取 ref
const instance = getCurrentInstance() // 【ref解决】使用 getCurrentInstance 取 ref
const route = useRoute()
const state = reactive({
lotteryDrawIndex: 0, // 最终转盘定格的索引
isShowlotteryDraw: true, // 是否抽奖完成
// 转盘背景配置
blocks: [{
padding: '20px',
imgs: [{
// src: 'https://img.iwave.net.cn/jeep/51c95637a377c3a12d09abe8b0f975e6.png',
src: require('@/assets/images/lottery_draw.png'),
width: 320,
height: 320,
rotate: true
}]
}],
// 每个扇形区域奖品配置
prizes: [...Array(10).keys()].map((index) => ({
fonts: [
{
text: index % 2 === 0 ? '谢谢参与' : '恭喜中奖',
top: '15%',
fontSize: '15px',
fontColor: '#ed1c24',
},
],
background: index % 2 === 0 ? '#fff5cc' : '#e9d6e9',
})),
// 抽奖按钮配置
buttons: [
{ radius: '50px', background: '#d034ac' },
{ radius: '45px', background: '#fe97b2' },
{
radius: '35px',
background: '#f04a07',
pointer: true,
fonts: [{ text: '开始', top: '-10px', fontColor: '#fff' }]
}
],
// 抽奖弹框是否展示
dialogVisible: false
})
// 获取正确题数、总题数
const { correct, total, examType } = route.query
const toLotteryDraw = () => {
state.dialogVisible = true
}
// 点击抽奖按钮会触发star回调
const startCallback = () => {
console.log('"开始抽奖"----', '开始抽奖')
// 调用抽奖组件的play方法开始游戏
// console.log('myLucky.value----', myLuckyRef.value) // 【ref问题】
// myLuckyRef.value?.play() // 【ref问题】
if (instance) {
instance.refs?.myLuckyRef?.play() // 【ref解决】
}
// this.$refs.myLucky.play() // 【ref】vue2写法
// 模拟调用接口异步抽奖
setTimeout(() => {
// 假设index(谢谢参与90%,恭喜中奖10%)
const index = `${Math.random()}`.slice(2, 3) * 1
state.lotteryDrawIndex = index === 1 ? 1 : 2
// 调用stop停止旋转并传递中奖索引
// this.$refs.myLuckyRef.stop(index) // 【ref】vue2写法
// myLuckyRef.value?.stop(index) // 【ref问题】
if (instance) {
instance.refs?.myLuckyRef?.stop(state.lotteryDrawIndex) // 【ref解决】
}
}, 3000)
}
// 抽奖结束会触发end回调
const endCallback = (prize) => {
console.log('"结束抽奖"----', '结束抽奖')
console.log(prize)
state.isShowlotteryDraw = false
}
return {
...toRefs(state),
correct,
total,
examType,
toLotteryDraw,
startCallback,
endCallback
}
}
}
</script>
<style scoped lang="less">
.exam-result {
.info {
margin: 0 0 5px;
padding: 10px;
background-color: white;
.progress {
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
position: relative;
.nut-circleprogress {
width: 145px !important;
height: 145px !important;
position: relative;
.progressDiv {
display: flex;
flex-direction: column;
align-items: center;
.accuracy {
color: #00000080;
background-color: #ffeded;
padding: 2px 8px;
font-size: 13px;
border-radius: 5px;
}
}
}
.circle {
position: absolute;
height: 145px;
width: 145px;
background-color: #ffeded;
border-radius: 50%;
top: 5px;
left: 50%;
transform: translate(-50%);
.circle1 {
position: absolute;
height: 115px;
width: 115px;
background-color: #ffffff;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.count {
background-color: #fffbf3;
margin-top: 10px;
padding-top: 5px;
color: #797e79;
font-size: 14px;
display: flex;
justify-content: space-around;
.centerDiv {
display: flex;
align-items: baseline;
justify-content: center;
.number {
margin-right: 5px;
font-size: 20px;
color: #FAAD14;
}
.text {
font-size: 12px;
}
}
}
}
.content {
margin-bottom: 10px;
background: white;
border-bottom: 1px solid #dcdcdc;
.result-table {
display: flex;
font-size: 16px;
font-weight: bolder;
color: #000;
.item {
display: flex;
align-items: baseline;
border-top: 0.5px solid #dcdcdc;
flex: 1;
font-size: 16px;
padding: 10px 10px 10px 15px;
color: #7f7f7f;
font-weight: normal;
&:nth-child(2n+1) {
border-right: 0.5px solid #dcdcdc;
}
.title {
margin-right: 5px;
font-size: 14px;
}
.unit {
font-size: 12px;
margin-left: 5px;
}
.time,
.total {
color: black;
font-size: 16px;
}
.correct {
color: #04be01;
font-size: 18px;
}
.error {
color: red;
font-size: 18px;
}
}
}
}
// 弹框样式
::v-deep .popup-center.round {
width: 90%;
.nut-dialog {
width: 100%;
padding: 20px 5px;
.nut-dialog__content {
max-height: unset;
.nut-icon-close {
position: absolute;
top: 15px;
right: 15px;
}
// 转盘结束展示结果
.result {
height: 80px;
line-height: 80px;
font-size: 20px;
font-weight: bold;
color: var(--color);
}
// 转盘
.myLucky {
display: inline-block;
}
}
}
}
// 抽奖弹框按钮
.lottery_draw_btn {
height: 25PX;
line-height: 25PX;
padding: 0 10px;
cursor: pointer;
font-size: 16px;
color: red;
}
}
</style>
页面效果
lucky-canvas 插件官方文档
lucky-canvas 插件官网
lucky-canvas 插件官网文档
可参考文档