uniapp 用view画抽奖转盘
约 832 字大约 3 分钟
2025-07-04
实现思路
因为是画转盘,而不是画扇形,所以可以绕过用 view 画扇形,直接画一个圆,然后画几条直径,把文字写入的时候旋转一下就可以了。
实现步骤(以 6 等分为例)
- 画转盘背景:
- 画一个圆,填充背景颜色;
- 用“子绝父相”布局,画一条直径,垂直居中;
- 再画一条直径,旋转 60 度;
- 画第三条直径,旋转 120 度;
- 在转盘背景上写文字:
- 以圆的外接矩形为外层容器,设置绝对布局和 flex 布局水平居中;
- 内层 view 设置绝对布局,写入数据;
- 由于绝对布局和外层容器设置了水平居中,所有的内层 view 都堆在中心,水平居中;
- 以中心为旋转点,内层 view 分别旋转 -60 度、-120 度;-180 度、-240 度、-300 度;
- 设置文字方向垂直,写入完成;
- 画转盘上指针:
- 样式可以自定义。
- 增加旋转动画。
实现效果
具体代码
添加了禁止连续点击多次
<!-- 抽奖转盘 -->
<template>
<view id="app">
<view class="title">{{ showTextList[result].title }}</view>
<view
class="container"
@click="startLottery"
:style="{ top: windowSize.height * 0.05 + 'px' }"
>
<!-- 转盘 -->
<view class="circle" :animation="animationData">
<view class="lines">
<view
v-for="(item, index) in lineList"
:style="{ transform: 'rotate(' + item.rotateDeg + 'deg)' }"
>
</view>
</view>
<view class="texts">
<view
v-for="(item, index) in showTextList"
:style="{ transform: 'rotate(' + item.rotateDeg + 'deg)' }"
>
{{ item.title }}
</view>
</view>
</view>
<!-- 指针 -->
<view class="pointer">
<view
class="pointer-triangle"
:style="{
borderBottomWidth: windowSize.width / 14 + 'px',
borderRightWidth: windowSize.width / 30 + 'px',
borderLeftWidth: windowSize.width / 30 + 'px',
}"
></view>
<view
class="pointer-circle"
:style="{
width: windowSize.width / 12 + 'px',
height: windowSize.width / 12 + 'px',
}"
>GO</view
>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
windowSize: {},
lineList: [],
showTextList: [],
isClicked: false,
animationData: {},
lastResult: 0,
result: 0,
deg: 0,
};
},
onLoad() {
this.initData();
},
mounted() {
this.windowSize = this.getWindowSize();
},
methods: {
/* 获取屏幕可用尺寸 */
getWindowSize() {
const windowInfo = uni.getWindowInfo();
let availableWindowSize = {
width: 0,
height: 0,
};
availableWindowSize.width = windowInfo.windowWidth; //px
availableWindowSize.height = windowInfo.windowHeight; //px
// console.log("windowSize", this.windowSize);
return availableWindowSize;
},
// 初始化数据
initData() {
this.lineList = [
{
rotateDeg: 0,
},
{
rotateDeg: 60,
},
{
rotateDeg: 120,
},
];
// 文字要逆时针旋转
this.showTextList = [
{
title: "1:跑步",
rotateDeg: 0,
},
{
title: "2:游泳",
rotateDeg: -60,
},
{
title: "3:666",
rotateDeg: -120,
},
{
title: "4:打拳",
rotateDeg: -180,
},
{
title: "5:剑道",
rotateDeg: -240,
},
{
title: "6:play piano",
rotateDeg: -300,
},
];
},
/* 开始旋转抽奖 */
startLottery() {
if (this.isClicked) {
//已经点击了
console.log("点击太频繁啦");
return;
}
this.isClicked = true;
let animation = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 2000,
timingFunction: "ease-in-out",
delay: 0,
});
this.animationData = animation;
this.animationData.rotate(this.randomNum()).step();
this.animationData = this.animationData.export();
setTimeout(() => {
this.isClicked = false;
}, 2000);
},
/* 获取随机数 */
randomNum() {
this.result = Math.floor(Math.random() * 6); //数组索引:[0,5]
if (this.result > this.lastResult) {
this.deg += 360 * 4 + (this.result - this.lastResult) * 60;
} else {
this.deg += 360 * 4 + 360 - (this.lastResult - this.result) * 60;
}
// console.log(`result:${this.result},deg:${this.deg}`);
this.lastResult = this.result;
return this.deg;
},
},
};
</script>
<style scoped>
.title {
text-align: center;
}
.container {
position: relative;
width: 100%;
/* background: rgba(87, 189, 106, 0.5); */
border: 1rpx solid skyblue;
}
.circle {
position: relative;
margin: auto;
width: 400rpx;
height: 400rpx;
border-radius: 50%;
border: 20rpx solid goldenrod;
background: rgba(0, 112, 46, 0.8);
}
.lines {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
.lines > view {
display: inline-block;
width: 100%;
height: 1%;
position: absolute;
transform-origin: center center;
background-color: #f5b362;
}
.texts {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
}
.texts view {
display: inline-block;
height: 96%;
color: white;
position: absolute;
writing-mode: vertical-lr;
transform-origin: center center;
/* background-color: #bd2d30; */
}
.pointer {
position: absolute;
margin: auto;
width: 100%;
height: 100%;
top: 0;
left: 0;
/* border: 5rpx solid yellow; */
}
.pointer-triangle,
.pointer-circle {
position: absolute;
z-index: 1;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: inline-block;
}
.pointer-triangle {
width: 0;
height: 0;
border-style: solid;
border-top-width: 0px;
border-color: transparent transparent #bd2d30 transparent;
transform: translate(-50%, -100%);
}
.pointer-circle {
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
color: white;
font-weight: bold;
background: #bd2d30;
}
</style>