<template>
<div class="turntable" ref="turntable">
<div class="myTurntable" :style="{transform: rotateAngle, transition: rotateTransition}">
<canvas id="canvas" ref="canvas">
当前浏览器版本过低,请使用其他浏览器尝试
</canvas>
<div class="prize-container">
<div v-for="(item, index) in prizeData" class="item" :key='index' :style="getRotateAngle(index)">
<slot name="item" :item="item"></slot>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'round-turntable',
mounted () {
this.init()
},
props: {
prizeData: {
required: true
},
rotateCircle: {
default: 6
},
turntableStyleOption: {
default: () => {
return {
// 背景色
prizeBgColors: ['#AE3EFF', '#4D3FFF', '#FC262C', '#3A8BFF', '#EE7602', '#FE339F'],
// 转盘的外边框颜色
borderColor: '#199301'
}
}
},
duringTime: {
default: 4.5
}
},
data () {
return {
// 开始转动的角度
startRotateDegree: 0,
rotateAngle: 0,
rotateTransition: ''
}
},
methods: {
// 根据index计算每一格要旋转的角度的样式
getRotateAngle (index) {
const angle = 360 / this.prizeData.length * index + (180 / this.prizeData.length)
return {
transform: `rotate(${angle}deg)`
}
},
// 初始化圆形转盘canvas
init () {
// 各种数据
const data = this.turntableStyleOption
const prizeNum = this.prizeData.length
const { prizeBgColors, borderColor } = data
// 开始绘画
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
const canvasW = this.$refs.canvas.width = this.$refs.turntable.clientWidth // 画板的高度
const canvasH = this.$refs.canvas.height = this.$refs.turntable.clientHeight // 画板的宽度
// translate方法重新映射画布上的 (0,0) 位置
ctx.translate(0, canvasH)
// rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
ctx.rotate(-90 * Math.PI / 180)
// 圆环的外圆的半径
const outRadius = canvasW / 2
// 圆环的内圆的半径
const innerRadius = 0
const baseAngle = Math.PI * 2 / prizeNum // 计算每个奖项所占角度数
ctx.clearRect(0, 0, canvasW, canvasH) // 去掉背景默认的黑色
ctx.strokeStyle = borderColor // 设置画图线的颜色
for (let index = 0; index < prizeNum; index++) {
const angle = index * baseAngle
ctx.fillStyle = prizeBgColors[index] // 设置每个扇形区域的颜色
ctx.beginPath() // 开始绘制
// 标准圆弧:arc(x,y,radius,startAngle,endAngle,anticlockwise)
ctx.arc(canvasW * 0.5, canvasH * 0.5, outRadius, angle, angle + baseAngle, false)
ctx.arc(canvasW * 0.5, canvasH * 0.5, innerRadius, angle + baseAngle, angle, true)
ctx.stroke() // 开始链线
ctx.fill() // 填充颜色
ctx.save() // 保存当前环境的状态
}
},
// 转动起来
rotate (index) {
// 运转时长
const duringTime = this.duringTime
const rotateAngle = this.startRotateDegree + this.rotateCircle * 360 + 360 - (180 / this.prizeData.length + 360 / this.prizeData.length * index) - this.startRotateDegree % 360
this.startRotateDegree = rotateAngle
this.rotateAngle = `rotate(${rotateAngle}deg)`
this.rotateTransition = `transform ${duringTime}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`
setTimeout(() => {
this.$emit('endRotation')
}, duringTime * 1000 + 500)
}
}
}
</script>
<style scoped lang="less">
.turntable {
/*background-color: red;*/
position: absolute;
width: 450px;
height: 440px;
left: 0;
top: 0;
text-align: center;
transform: translateZ(0);
.myTurntable {
width: 450px;
height: 440px;
position: absolute;
left: 0;
top: 0;
}
.prize-container {
position: absolute;
left: 25%;
top: 0;
width: 50%;
height: 50%;
.item {
/*background: pink;*/
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
transform-origin: center bottom;
}
}
}
</style>
- 引用
import roundTurntable from './components/roundTurntable';
- 声明
components: { roundTurntable },
- 调用
<round-turntable ref="roundTurntable" :prizeData="prizeData" :rotateCircle="rotateCircle" :duringTime="duringTime" :turntableStyleOption="turntableStyleOption" @endRotation="endRotation" class="turntable"> <template slot="item" slot-scope="scope"> <div class="turntable-name">{{ scope.item.prizeName }}</div> <div class="turntable-img"> <img :src="scope.item.prizeImg"> </div> </template> </round-turntable>
data() { return { // 转盘上的奖品数据 prizeData: [ { id: 1, prizeName: '2000元京东券', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/1.png', }, { id: 2, prizeName: '300元京东券', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/7.png', }, { id: 3, prizeName: '50个比特币', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/3.png', }, { id: 4, prizeName: '50元话费券', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/4.png', }, { id: 5, prizeName: '100元话费券', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/5.png', }, { id: 6, prizeName: '100个比特币', prizeImg: 'http://demo.sc.chinaz.net/Files/DownLoad/webjs1/201803/jiaoben5789/images/6.png', } ], // 转动的圈数 rotateCircle: 6, // 转动需要持续的时间(s) duringTime: 4.5, // 转盘样式的选项 turntableStyleOption: { // 背景色 prizeBgColors: ['#AE3EFF', '#4D3FFF', '#FC262C', '#3A8BFF', '#EE7602', '#FE339F'], // 转盘的外边框颜色 borderColor: '#199301', }, } }, methods: { // 已经转动完转盘触发的函数 endRotation() { // 提示中奖 alert(`恭喜您获奖啦,您的奖品是:${this.prizeData[this.prizeIndex].prizeName}`); }, },
.turntable { position: absolute; left: calc(50% - 200px); top: calc(50% - 200px); width: 400px; height: 400px; } .turntable-name { /*background: pink;*/ position: absolute; left: 10px; top: 20px; width: calc(100% - 20px); font-size: 26px; text-align: center; color: #fff; } .turntable-img { position: absolute; /*要居中就要50% - 宽度 / 2*/ left: calc(50% - 80px / 2); top: 60px; width: 80px; height: 80px; img { display: inline-block; width: 100%; height: 100%; } }
转自:https://github.com/LiaPig/vue-round-turntable 推荐一个抽奖插件lucky-canvas:在 Vue 中使用 | 基于 Js / JQuery / Vue / React / 微信小程序 / uni-app / Taro 的【大转盘 & 九宫格】抽奖插件