更新记录

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种扇区渲染形态,支持可视化参数调节、权重随机抽奖、自定义画布尺寸、中心头像、条目图文弹窗预览、中途终止旋转等全套能力。可访问下面二维码体验转盘交互:

超级转盘

二、核心功能亮点

  1. 四种扇区样式自由切换
  • CIRCLE:标准圆形均分扇区,传统转盘样式
  • OUTWARD:全部扇区圆弧向外凸起
  • INWARD:全部扇区圆弧向内凹陷
  • ALTERNATE:奇偶扇区凹凸交替,层次感更强
  1. 内置可视化参数控制面板 提供滑块实时调整转盘半径、弧线曲率、弧线偏移,支持一键展开/收起面板
  2. 权重概率抽奖 每条条目配置 weight 权重,权重越大中奖概率越高;支持旋转前指定条目id
  3. 完整自定义配置项 画布尺寸(支持 px/rpx/vw/vh)、转盘半径、动画时长、中心Logo、单扇区自定义背景色、条目配图+描述文本
  4. 双交互逻辑
  • 点击转盘中心/中心头像:触发转盘旋转
  • 直接点击任意扇区:弹窗快速查看该条目详情,不触发旋转动画
  1. 流畅缓动动画 前半段匀速高速旋转,末尾缓动减速精准定格目标条目;支持手动一键终止旋转
  2. 中奖弹窗详情展示 转盘旋转结束自动弹出弹窗,展示条目名称、描述、配图;图片支持点击全屏预览
  3. 条目文字显示顺序 转盘中间水平以上部分条目文字从外向内展示,下半部分从内向外展示,做到始终符合阅读习惯,受限于转盘大小,最多展示10个文字,点击条目可查看完整条目信息
  4. 多端高清兼容 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事件,父组件可监听:

  1. arcCurvatureChange
    • 触发时机:拖动弧线曲率滑块修改数值
    • 回调参数:当前曲率数值 Number
  2. arcOffsetChange
    • 触发时机:拖动弧线偏移滑块修改数值
    • 回调参数:当前偏移数值 Number
  3. wheelRadiusChange
    • 触发时机:拖动转盘半径滑块修改数值
    • 回调参数:当前转盘半径数值 Number
  4. showControlSettingChange
    • 触发时机:点击「显示 / 隐藏参数设置」切换面板状态
    • 回调参数:布尔值,true = 展开面板,false = 收起面板

七、使用注意事项

  1. canvas-id 在当前页面必须唯一,多个转盘组件需分配不同 id
  2. itemList 条目数量最少 3 条,不足 3 条会弹出 toast 禁止抽奖
  3. rotationTotalTime 最小限制 2 秒,传入小于 2 秒数值会拦截操作并提示
  4. arcDirectionType != CIRCLE 时,曲率、偏移滑块才会显示并生效
  5. 小程序使用网络图片时,需在后台配置 downloadFile 域名白名单
  6. 组件自动做高清 dpr 缩放处理,无需手动处理 canvas 模糊问题
  7. 转盘旋转过程中重复点击中心、扇区会拦截操作,提示「请勿重复操作」

八、兼容平台

  • 支持微信小程序、H5、App(其它小程序、ios\鸿蒙设备需自行测试可行性)
  • 仅支持 uni-app Vue3 setup 语法,不兼容 Vue2 选项式项目

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。