uni-app初探之幸运轮盘

uni-app以其“一次开发,多端覆盖”的理念深得大家青睐,并且生态环境丰富,本文以一个幸运轮盘小例子,简述canvas的相关操作,仅供学习分享使用,如有不足之处,还请指正。

什么是canvas?

canvas又称画布,为uni-app提供自定义绘制的区域,通常用于图表或者图片的处理。在uni-app开发中,如果要在canvas中进行绘制,需要通过CanvasContext完成。

canvas相关知识点

canvas属性说明【canvas-id 在同一页面中不可重复】

CanvasContext的定义通过uni-app提供的API【uni.createCanvasContext(canvasId, this)】完成,如下所示:

 在canvas上进行绘制,主要通过CanvasContex对象进行。关于CanvasContext的使用方法,可参考官方文档

示例效果图

在Chrome浏览器上,如下所示:

在Android手机上,如下图所示:

核心源代码

在uni-app开发中,一个功能可以封装成一个控件,便于维护和调用。

本例Lottery控件的template源码如下:

<template>
    <view class="content1">
        <canvas type="2D" canvas-id="canvas" id="canvas" :style="canvasStyle">

        </canvas>
        <image :src="inLottery?'../../static/img/start_disabled.png':'../../static/img/start.png'" id="start" @tap="playReward"></image>
        <view class="bottom1">
            <image src="../../static/img/xiaolian.png" class="smile"></image>
            <view class="winner">{{winner}}</view>
        </view>

    </view>
</template>

本例Lottery控件的JavaScript源码如下:

<script>
    var ctx = null;
    export default {
        props: {
            lwidth: {
                type: Number,
                default: 100,

            },
            lheight: {
                type: Number,
                default: 100
            },
            inLottery: {
                type: Boolean,
                default: false
            },

            parts: {
                type: Array,
                default: function() {
                    return [{
                            id: 1,
                            name: '香蕉',
                            img: '',
                            color: "#AABBCC"
                        },
                        {
                            id: 2,
                            name: '苹果',
                            img: '',
                            color: "#FFCCFF"
                        },
                        {
                            id: 3,
                            name: '梨子',
                            img: '',
                            color: "#FFFFFF"
                        },
                        {
                            id: 4,
                            name: '青瓜',
                            img: '',
                            color: "#FFCCFF"
                        },
                        {
                            id: 5,
                            name: '番茄',
                            img: '',
                            color: "#FFFFFF"
                        }
                    ]
                }
            }
        },
        data() {
            return {
                winner:"请抽奖"
            };
        },
        computed: {
            canvasStyle() {
                return {
                    width: (this.lwidth) + "px",
                    height: (this.lheight) + "px"
                };
            },

        },
        methods: {
            initLottery:function(ctx,angleTo){

                const len = this.parts.length; //数组长度
                if (len == 0) {
                    return;
                }
                var center_x = this.lwidth / 2;
                var center_y = this.lheight / 2;
                var total = 2 * Math.PI; //总度数为2π
                var Angle = total / len; //平均值
                var radius = center_x - 14;
                center_x = center_x;
                center_y = center_y;
                angleTo = angleTo || 0;
                ctx.clearRect(0,0, this.lwidth, this.lheight);
                ctx.translate(center_x, center_y);
                ctx.setFontSize(14);
                ctx.setLineWidth(14);
                ctx.save();
                //旋转画布
                ctx.rotate(angleTo * Math.PI / 180);
                //
                var beginAngle = 2 * Math.PI / 360 * (-90);
                //先画外圆
                ctx.setStrokeStyle("#ffaa00");
                ctx.arc(0, 0, radius + 3, 0, Math.PI * 2);
                ctx.stroke();
                //画装饰点
                for (var i = 0; i < 24; i++) {
                    // 装饰点 圆心 坐标计算
                    ctx.beginPath();
                    var r = radius + 6;
                    var xr = r * Math.cos(beginAngle);
                    var yr = r * Math.sin(beginAngle);

                    ctx.fillStyle = "#FFFFFF";
                    ctx.arc(xr, yr, 4, 0, 2 * Math.PI);
                    ctx.fill();

                    beginAngle += (2 * Math.PI / 360) * (360 / 24);

                }
                ctx.setLineWidth(0.1);
                beginAngle = 2 * Math.PI / 360 * (-90);
                //绘制填充形状
                for (var i = 0; i < len; i++) {
                    // console.log("color = "+this.parts[i].color);
                    // console.log("beginAngle="+beginAngle);
                    ctx.save();
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.setStrokeStyle(this.parts[i].color);
                    ctx.setFillStyle(this.parts[i].color);

                    ctx.arc(0, 0, radius, beginAngle, beginAngle + Angle, false);
                    //ctx.stroke();
                    ctx.fill();
                    ctx.save();
                    beginAngle = beginAngle + Angle;
                }
                beginAngle = 0; //Angle / 2;
                for (var i = 0; i < len; i++) {
                    var ry = -(center_x / 2) - 25;
                    //绘制旋转文字
                    ctx.rotate((beginAngle + (Angle * 0.5))); //顺时针旋转
                    ctx.setTextAlign("center");
                    ctx.setFillStyle("#AA00CC");
                    ctx.fillText(this.parts[i].name, 0, ry);

                    ctx.restore();
                    beginAngle = beginAngle + Angle;
                }
                ctx.save();
                ctx.beginPath();
                ctx.arc(0, 0, 8, 0, Math.PI * 2);
                ctx.setFillStyle("#FFFFFF");
                ctx.fill();
                ctx.draw();
            },
            playReward:function(){
                var len = this.parts.length; //数组长度
                if (len == 0) {
                    return;
                }
                var angle = 360/len ;
                var num =Math.floor(Math.random()*len);
                //num= num%len;
                angle = num * angle + angle / 2;
                angle = angle || 0;
                angle = 360-angle;
                angle += 1440;
                console.log("angle = "+angle +",num = "+num);
                var that = this;
                var count = 1;
                // 基值(减速)
                var baseStep = 50;
                // 起始滚动速度
                var baseSpeed =1;
                var timer = setInterval(function(){
                    console.log("count = "+count);
                    that.initLottery(that.ctx,count) ;
                    if (count == angle) {
                        clearInterval(timer);
                        that.winner = "当前奖品为:"+that.parts[num].name;
                    }
                    count =  count + baseStep * (((angle - count) / angle) > baseSpeed ? baseSpeed : ((angle - count) / angle))+0.1;
                    if (angle - count < 0.5) {
                        count = angle;
                    }
                },25);
            }
        },
        // 组件内么有onReady和onLoad等生命周期
        mounted: function() {
            this.ctx = uni.createCanvasContext("canvas");
            this.initLottery(this.ctx,0);
        }
    }
</script>

 本例Lottery控件的CSS源码如下:

<style>
    .content1 {
        width: 100%;
        height: 100%;
        text-align: center;
        display: flex;
        flex-direction: column;
        align-items: center;
        position: relative;
    }

    #canvas {
        left: 2rpx;
        top: 2rpx;
    }

    #start {
        position: absolute;
        width: 110rpx;
        height: 150rpx;
        cursor: pointer;
        top: 240rpx;
    }
    .bottom1{
        display: flex;
        flex-direction: row;
        justify-content: center;
        justify-content: center;
    }
    .winner{
        height: 70rpx;
        vertical-align: middle;
        padding-top: 10rpx;
        color: #FFFFFF;
    }
    .smile{
        width: 70rpx;
        height: 70rpx;
    }
</style>

 本例index页面调用组件,代码如下:

<template>
    <view class="content">
        <view class="top"></view>
        <lottery  class="lottery" :lwidth="lwidth" :lheight="lheight"></lottery>
        <view class="bottom">Provider By Alan.hsiang</view>
    </view>
</template>

<script>
    import lottery from "@/components/Lottery/Lottery.vue"
    export default {
        components:{
            lottery
        },
        data() {
            return {
                title: 'Hello',
                lwidth:300,
                lheight:300
            }
        },
        onLoad() {

        },
        methods: {

        }
    }
</script>

<style>
    .content {
        display: flex;
        flex-direction: column;
        /* align-items: center; */
        /* justify-content: center; */
        background-image: url(../../static/img/bg.jpg);
        background-position: center;
        background-repeat: no-repeat;
        background-size: cover;
        height: 100%;
        width: 100%;
    }
    .top{
        height: 35%;
        width: 100%;
    }
    .lottery{
        /* position: absolute; */
        /* top: 200rpx; */
        /* bottom: 200rpx; */
        margin: 2rpx;
        width: 100%;
        height: 700rpx;
    }
    .bottom{
        position: absolute;
        bottom: 10rpx;
        color: #FFFFFF;
        width: 100%;
        text-align: center;
    }
</style>

另外为了页面显示完整,需要在App.vue中定义页面显示100%,如下所示:

<script>
    export default {
        onLaunch: function() {
            console.log('App Launch')
        },
        onShow: function() {
            console.log('App Show')
        },
        onHide: function() {
            console.log('App Hide')
        }
    }
</script>

<style>
    /*每个页面公共css */
    uni-page-body,#app {width:100%;height: 100%;}
    page{
        width: 100%;
        height: 100%;
    }
</style>

备注

八声甘州·对潇潇暮雨洒江天
【作者】柳永 【朝代】宋

对潇潇暮雨洒江天,一番洗清秋。
渐霜风凄紧,关河冷落,残照当楼。
是处红衰翠减,苒苒物华休。
惟有长江水,无语东流。

不忍登高临远,望故乡渺邈,归思难收。
叹年来踪迹,何事苦淹留?
想佳人、妆楼颙望,误几回、天际识归舟。
争知我,倚栏杆处,正恁凝愁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老码识途呀

写作不易,多谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值