目录
需求背景需求实现实现过程图片示意实现代码 页面效果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 插件官网文档
可参考文档