uniapp 用view画抽奖转盘

实现思路:

  因为是画转盘,而不是画扇形,所以可以绕过用view画扇形,直接画一个圆,然后画几条直径,把文字写入的时候旋转一下就可以了。

以6等分为例,实现步骤:

  1. 画转盘背景:
    • 画一个圆,填充背景颜色;
    • 用“子绝父相”布局,画一条直径,垂直居中;
    • 再画一条直径,旋转60度;
    • 画第三条直径,旋转120度;
  2. 在转盘背景上写文字:
    • 以圆的外接矩形为外层容器,设置绝对布局和flex布局水平居中;
    • 内层view设置绝对布局,写入数据;
    • 由于绝对布局和外层容器设置了水平居中,所有的内层view都堆在中心,水平居中;
    • 以中心为旋转点,内层view分别旋转 -60度、-120度;-180度、-240度、-300度;
    • 设置文字方向垂直,写入完成;
  3. 画转盘上指针:
    • 样式可以自定义。
  4. 增加旋转动画。

实现效果:

 

具体代码如下(添加了禁止连续点击多次):

<!-- 抽奖转盘 -->
<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>

 

posted @ 2023-01-30 11:33  sunshine233  阅读(1582)  评论(0编辑  收藏  举报