更新记录
1.0.0(2026-08-18) 下载此版本
初次发布,详情如下
平台兼容性
uni-app(3.8.2)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | √ | √ | - | √ | - | √ | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | - | - | - | - | - | - | - | - | - | - | - |
qihuis-canvas-wheel 自定义多彩异形转盘
一、组件简介
基于 uni-app Canvas 2D 开发的多功能抽奖转盘组件,使用 Vue3 setup 语法,兼容小程序、H5、App 多端。 内置4种扇区渲染形态,支持可视化参数调节、权重随机抽奖、自定义画布尺寸、中心头像、条目图文弹窗预览、中途终止旋转等全套能力。可访问下面二维码体验转盘交互:

二、核心功能亮点
- 四种扇区样式自由切换
CIRCLE:标准圆形均分扇区,传统转盘样式OUTWARD:全部扇区圆弧向外凸起INWARD:全部扇区圆弧向内凹陷ALTERNATE:奇偶扇区凹凸交替,层次感更强
- 内置可视化参数控制面板 提供滑块实时调整转盘半径、弧线曲率、弧线偏移,支持一键展开/收起面板
- 权重概率抽奖 每条条目配置 weight 权重,权重越大中奖概率越高;支持旋转前指定条目id
- 完整自定义配置项 画布尺寸(支持 px/rpx/vw/vh)、转盘半径、动画时长、中心Logo、单扇区自定义背景色、条目配图+描述文本
- 双交互逻辑
- 点击转盘中心/中心头像:触发转盘旋转
- 直接点击任意扇区:弹窗快速查看该条目详情,不触发旋转动画
- 流畅缓动动画 前半段匀速高速旋转,末尾缓动减速精准定格目标条目;支持手动一键终止旋转
- 中奖弹窗详情展示 转盘旋转结束自动弹出弹窗,展示条目名称、描述、配图;图片支持点击全屏预览
- 条目文字显示顺序 转盘中间水平以上部分条目文字从外向内展示,下半部分从内向外展示,做到始终符合阅读习惯,受限于转盘大小,最多展示10个文字,点击条目可查看完整条目信息
- 多端高清兼容 Canvas2D 自动处理设备dpr,避免画布文字、图形模糊;全端统一渲染逻辑
三、快速使用示例
页面完整示例代码
<template>
<view class="container">
<view class="wheel-action">
<view class="style-selector">
<uni-data-select v-model="wheelInfo.wheelStyle" :localdata="wheelStyleOptions" :clear="false" ></uni-data-select>
</view>
<button size="mini" @click="stopRotation()">终止转动</button>
</view>
<!-- 圆弧类型:circle:标准圆,outward:朝外,inward:朝内,alternate:交替 -->
<qihuis-canvas-wheel ref="wheelRef"
canvas-id="spin-wheel"
:wheel-title="wheelInfo.title"
canvas-width="90vw"
:arc-direction-type="wheelInfo.wheelStyle"
:show-control-setting="true"
:custome-arc-curvature="wheelInfo.arcCurvature"
:custome-arc-offset="wheelInfo.arcOffset"
:custome-wheel-radius="wheelInfo.wheelRadius"
:rotation-total-time="wheelInfo.duration"
:center-avatar-url="wheelInfo.centerAvatarUrl"
:show-resule-dialog="true"
:item-list="wheelInfo.wheelItems"
:handle-wheel-stop-rotation="handleWheelStopRotation"
:click-wheel-fun="clickWheel" />
</view>
</template>
<script setup>
import { onLoad,onUnload } from '@dcloudio/uni-app';
import { ref } from 'vue'
const wheelRef = ref(null)
const wheelInfo = ref({})
const centerAvatarUrl = ref("/static/logo.png")
const wheelStyleOptions = ref([
{value: "CIRCLE", text: "标准圆"},
{value: "OUTWARD", text: "圆弧朝外"},
{value: "INWARD", text: "圆弧朝内"},
{value: "ALTERNATE", text: "圆弧交替"}
])
onLoad((e) => {
uni.$on("arcCurvatureChange",arcCurvatureChange)
uni.$on("arcOffsetChange",arcOffsetChange)
uni.$on("wheelRadiusChange",wheelRadiusChange)
uni.$on("showControlSettingChange",showControlSettingChange)
setTimeout(()=>{
wheelInfo.value = {
title: "吃什么1",
centerAvatarUrl: "/static/logo.png",
duration: 3,
wheelStyle: "OUTWARD",
wheelRadius: 150,
arcCurvature: 1,
arcOffset: 0,
wheelItems: [
{
"id":1,
"text": "炒萝卜",
"color": "",
"weight": 1,
"picUrl": "/static/logo.png",
"description": "炒萝卜炒萝卜炒萝卜"
}, {
"id":2,
"text": "炒白菜",
"color": "",
"weight": 1,
"picUrl": "",
"description": "炒白菜炒白菜炒白菜"
}, {
"id":3,
"text": "萝卜炖白菜",
"color": "",
"weight": 1,
"picUrl": "",
"description": ""
}, {
"id":4,
"text": "白菜炖萝卜",
"color": "",
"weight": 1,
"picUrl": "",
"description": ""
}, {
"id":5,
"text": "萝卜开会",
"color": "",
"weight": 1,
"picUrl": "",
"description": ""
},{
"id":6,
"text": "泡面",
"color": "",
"weight": 1,
"picUrl": "",
"description": ""
}
]
}
},1000)
})
onUnload(()=>{
uni.$off("arcCurvatureChange",arcCurvatureChange)
uni.$off("arcOffsetChange",arcOffsetChange)
uni.$off("wheelRadiusChange",wheelRadiusChange)
uni.$off("showControlSettingChange",showControlSettingChange)
})
//拖动弧线曲率滑块修改数值
function arcCurvatureChange(result){
console.log(result)
}
//拖动弧线偏移滑块修改数值
function arcOffsetChange(result){
console.log(result)
}
//拖动转盘半径滑块修改数值
function wheelRadiusChange(result){
console.log(result)
}
//点击「显示 / 隐藏参数设置」切换面板状态
function showControlSettingChange(result){
console.log(result)
}
//转盘结束时选中的条目信息
function handleWheelStopRotation(result){
console.log(result)
}
//点击转盘中心区域触发的回调
function clickWheel(){
//可以指定条目的id
// wheelRef.value.startRotation(1)
wheelRef.value.startRotation()
}
function stopRotation(){
wheelRef.value.stopRotation()
}
</script>
<style scoped>
.container {
background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 30rpx;
}
.wheel-action{
width: 100%;
padding: 0 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.style-selector{
width: 50vw;
margin: 30rpx 0;
}
</style>
四、Props 属性完整说明
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| canvasId | String | - | Canvas 唯一标识,必填,页面多转盘时必须设置不同 id |
| wheelTitle | String | - | 转盘顶部标题文字 |
| canvasWidth | Number / String | 350 | 高度共用此数据,画布整体尺寸,支持单位:px /rpx/vw /vh;纯数字默认 px |
| arcDirectionType | String | CIRCLE | 扇区圆弧渲染类型:CIRCLE = 标准圆形,OUTWARD = 全部圆弧朝外凸起,INWARD = 全部圆弧向内凹陷,ALTERNATE = 奇偶扇区凹凸交替 |
| showControlSetting | Boolean | true | 页面初始化时是否默认展开参数调节面板 |
| customeWheelRadius | Number / String | 150 | 转盘基础半径,面板滑块可实时修改,支持单位:px /rpx/vw /vh;纯数字默认 px |
| customeArcCurvature | Number | 1.0 | 弧线曲率,取值范围 0.2\~2.0,仅非标准圆模式生效;数值越大凹凸幅度越强 |
| customeArcOffset | Number | 0 | 弧线偏移微调,取值范围 - 30\~30,仅非标准圆模式生效 |
| rotationTotalTime | Number | 3 | 转盘完整动画总时长,单位秒,最小限制 2 秒 |
| centerAvatarUrl | String | - | 转盘中心圆形头像图片地址,不传则显示默认文字「转盘」 |
| showResuleDialog | Boolean | true | 抽奖结束后是否自动弹窗展示中奖结果,可设置为false,然后在handleWheelStopRotation回调函数自定义处理中奖结果 |
| clickWheelFun | Function | null | 点击转盘中心头像触发的回调函数,需要在回调内再次调用startRotation启动转盘旋转 |
| handleWheelStopRotation | Function | null | 转盘完全停止后的回调,参数为中奖条目完整对象 |
| itemList | Array | 内置 6 条默认数据 | 条目数组,单条对象字段见下表 |
itemList 单条条目对象字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Number | 条目唯一 id,指定必中时依靠 id 匹配 |
| text | String | 扇区内部展示的条目名称 ,弹窗内展示 |
| color | String | 自定义当前扇区背景色,为空自动使用内置配色数组 |
| weight | Number | 中奖权重,数值越大中奖概率越高;所有权重 ≤0 时纯随机 |
| picUrl | String | 条目配图地址,弹窗展示,支持点击全屏预览 |
| description | String | 条目详情描述文字,弹窗内展示 |
五、组件对外暴露实例方法
通过 ref="wheelRef" 获取组件实例调用以下方法:
1. startRotation(prizeId)
- 作用:启动转盘旋转动画
- 参数:prizeId 可选,传入则强制命中对应 id 条目;不传则按权重随机抽取
- 限制:旋转中禁止重复调用;条目个数不可小于3条,传入总时长 < 2 秒会拦截并弹窗提示
2. stopRotation()
- 作用:立刻终止当前正在执行的转盘旋转动画
3. getRandomItemIdByWeight()
- 作用:仅根据权重计算随机条目 id,不启动转盘,可外部单独获取随机条目
六、组件 $emit 抛出事件
修改控制面板参数、切换面板显示状态时触发emit事件,父组件可监听:
- arcCurvatureChange
- 触发时机:拖动弧线曲率滑块修改数值
- 回调参数:当前曲率数值 Number
- arcOffsetChange
- 触发时机:拖动弧线偏移滑块修改数值
- 回调参数:当前偏移数值 Number
- wheelRadiusChange
- 触发时机:拖动转盘半径滑块修改数值
- 回调参数:当前转盘半径数值 Number
- showControlSettingChange
- 触发时机:点击「显示 / 隐藏参数设置」切换面板状态
- 回调参数:布尔值,true = 展开面板,false = 收起面板
七、使用注意事项
- canvas-id 在当前页面必须唯一,多个转盘组件需分配不同 id
- itemList 条目数量最少 3 条,不足 3 条会弹出 toast 禁止抽奖
- rotationTotalTime 最小限制 2 秒,传入小于 2 秒数值会拦截操作并提示
- 仅
arcDirectionType != CIRCLE时,曲率、偏移滑块才会显示并生效 - 小程序使用网络图片时,需在后台配置 downloadFile 域名白名单
- 组件自动做高清 dpr 缩放处理,无需手动处理 canvas 模糊问题
- 转盘旋转过程中重复点击中心、扇区会拦截操作,提示「请勿重复操作」
八、兼容平台
- 支持微信小程序、H5、App(其它小程序、ios\鸿蒙设备需自行测试可行性)
- 仅支持 uni-app Vue3 setup 语法,不兼容 Vue2 选项式项目

收藏人数:
下载插件并导入HBuilderX
赞赏(0)
下载 5
赞赏 0
下载 12518165
赞赏 1943
赞赏
京公网安备:11010802035340号