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源码如下:

 1 <template>
 2     <view class="content1">
 3         <canvas type="2D" canvas-id="canvas" id="canvas" :style="canvasStyle">
 4 
 5         </canvas>
 6         <image :src="inLottery?'../../static/img/start_disabled.png':'../../static/img/start.png'" id="start" @tap="playReward"></image>
 7         <view class="bottom1">
 8             <image src="../../static/img/xiaolian.png" class="smile"></image>
 9             <view class="winner">{{winner}}</view>
10         </view>
11         
12     </view>
13 </template>
View Code

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

  1 <script>
  2     var ctx = null;
  3     export default {
  4         props: {
  5             lwidth: {
  6                 type: Number,
  7                 default: 100,
  8 
  9             },
 10             lheight: {
 11                 type: Number,
 12                 default: 100
 13             },
 14             inLottery: {
 15                 type: Boolean,
 16                 default: false
 17             },
 18             
 19             parts: {
 20                 type: Array,
 21                 default: function() {
 22                     return [{
 23                             id: 1,
 24                             name: '香蕉',
 25                             img: '',
 26                             color: "#AABBCC"
 27                         },
 28                         {
 29                             id: 2,
 30                             name: '苹果',
 31                             img: '',
 32                             color: "#FFCCFF"
 33                         },
 34                         {
 35                             id: 3,
 36                             name: '梨子',
 37                             img: '',
 38                             color: "#FFFFFF"
 39                         },
 40                         {
 41                             id: 4,
 42                             name: '青瓜',
 43                             img: '',
 44                             color: "#FFCCFF"
 45                         },
 46                         {
 47                             id: 5,
 48                             name: '番茄',
 49                             img: '',
 50                             color: "#FFFFFF"
 51                         }
 52                     ]
 53                 }
 54             }
 55         },
 56         data() {
 57             return {
 58                 winner:"请抽奖"
 59             };
 60         },
 61         computed: {
 62             canvasStyle() {
 63                 return {
 64                     width: (this.lwidth) + "px",
 65                     height: (this.lheight) + "px"
 66                 };
 67             },
 68             
 69         },
 70         methods: {
 71             initLottery:function(ctx,angleTo){
 72                 
 73                 const len = this.parts.length; //数组长度
 74                 if (len == 0) {
 75                     return;
 76                 }
 77                 var center_x = this.lwidth / 2;
 78                 var center_y = this.lheight / 2;
 79                 var total = 2 * Math.PI; //总度数为2π
 80                 var Angle = total / len; //平均值
 81                 var radius = center_x - 14;
 82                 center_x = center_x;
 83                 center_y = center_y;
 84                 angleTo = angleTo || 0;
 85                 ctx.clearRect(0,0, this.lwidth, this.lheight);
 86                 ctx.translate(center_x, center_y);
 87                 ctx.setFontSize(14);
 88                 ctx.setLineWidth(14);
 89                 ctx.save();
 90                 //旋转画布
 91                 ctx.rotate(angleTo * Math.PI / 180);
 92                 //
 93                 var beginAngle = 2 * Math.PI / 360 * (-90);
 94                 //先画外圆
 95                 ctx.setStrokeStyle("#ffaa00");
 96                 ctx.arc(0, 0, radius + 3, 0, Math.PI * 2);
 97                 ctx.stroke();
 98                 //画装饰点
 99                 for (var i = 0; i < 24; i++) {
100                     // 装饰点 圆心 坐标计算
101                     ctx.beginPath();
102                     var r = radius + 6;
103                     var xr = r * Math.cos(beginAngle);
104                     var yr = r * Math.sin(beginAngle);
105                 
106                     ctx.fillStyle = "#FFFFFF";
107                     ctx.arc(xr, yr, 4, 0, 2 * Math.PI);
108                     ctx.fill();
109                 
110                     beginAngle += (2 * Math.PI / 360) * (360 / 24);
111                 
112                 }
113                 ctx.setLineWidth(0.1);
114                 beginAngle = 2 * Math.PI / 360 * (-90);
115                 //绘制填充形状
116                 for (var i = 0; i < len; i++) {
117                     // console.log("color = "+this.parts[i].color);
118                     // console.log("beginAngle="+beginAngle);
119                     ctx.save();
120                     ctx.beginPath();
121                     ctx.moveTo(0, 0);
122                     ctx.setStrokeStyle(this.parts[i].color);
123                     ctx.setFillStyle(this.parts[i].color);
124                 
125                     ctx.arc(0, 0, radius, beginAngle, beginAngle + Angle, false);
126                     //ctx.stroke();
127                     ctx.fill();
128                     ctx.save();
129                     beginAngle = beginAngle + Angle;
130                 }
131                 beginAngle = 0; //Angle / 2;
132                 for (var i = 0; i < len; i++) {
133                     var ry = -(center_x / 2) - 25;
134                     //绘制旋转文字
135                     ctx.rotate((beginAngle + (Angle * 0.5))); //顺时针旋转
136                     ctx.setTextAlign("center");
137                     ctx.setFillStyle("#AA00CC");
138                     ctx.fillText(this.parts[i].name, 0, ry);
139                 
140                     ctx.restore();
141                     beginAngle = beginAngle + Angle;
142                 }
143                 ctx.save();
144                 ctx.beginPath();
145                 ctx.arc(0, 0, 8, 0, Math.PI * 2);
146                 ctx.setFillStyle("#FFFFFF");
147                 ctx.fill();
148                 ctx.draw();
149             },
150             playReward:function(){
151                 var len = this.parts.length; //数组长度
152                 if (len == 0) {
153                     return;
154                 }
155                 var angle = 360/len ; 
156                 var num =Math.floor(Math.random()*len);
157                 //num= num%len;
158                 angle = num * angle + angle / 2;
159                 angle = angle || 0;
160                 angle = 360-angle;
161                 angle += 1440;
162                 console.log("angle = "+angle +",num = "+num);
163                 var that = this;
164                 var count = 1;
165                 // 基值(减速)
166                 var baseStep = 50;
167                 // 起始滚动速度
168                 var baseSpeed =1;
169                 var timer = setInterval(function(){
170                     console.log("count = "+count);
171                     that.initLottery(that.ctx,count) ;
172                     if (count == angle) {
173                         clearInterval(timer);
174                         that.winner = "当前奖品为:"+that.parts[num].name;
175                     }
176                     count =  count + baseStep * (((angle - count) / angle) > baseSpeed ? baseSpeed : ((angle - count) / angle))+0.1;
177                     if (angle - count < 0.5) {
178                         count = angle;
179                     }
180                 },25);
181             }
182         },
183         // 组件内么有onReady和onLoad等生命周期
184         mounted: function() {
185             this.ctx = uni.createCanvasContext("canvas");
186             this.initLottery(this.ctx,0);
187         }
188     }
189 </script>
View Code

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

 1 <style>
 2     .content1 {
 3         width: 100%;
 4         height: 100%;
 5         text-align: center;
 6         display: flex;
 7         flex-direction: column;
 8         align-items: center;
 9         position: relative;
10     }
11 
12     #canvas {
13         left: 2rpx;
14         top: 2rpx;
15     }
16 
17     #start {
18         position: absolute;
19         width: 110rpx;
20         height: 150rpx;
21         cursor: pointer;
22         top: 240rpx;
23     }
24     .bottom1{
25         display: flex;
26         flex-direction: row;
27         justify-content: center;
28         justify-content: center;
29     }
30     .winner{
31         height: 70rpx;
32         vertical-align: middle;
33         padding-top: 10rpx;
34         color: #FFFFFF;
35     }
36     .smile{
37         width: 70rpx;
38         height: 70rpx;
39     }
40 </style>
View Code

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

 1 <template>
 2     <view class="content">
 3         <view class="top"></view>
 4         <lottery  class="lottery" :lwidth="lwidth" :lheight="lheight"></lottery>
 5         <view class="bottom">Provider By Alan.hsiang</view>
 6     </view>
 7 </template>
 8 
 9 <script>
10     import lottery from "@/components/Lottery/Lottery.vue"
11     export default {
12         components:{
13             lottery
14         },
15         data() {
16             return {
17                 title: 'Hello',
18                 lwidth:300,
19                 lheight:300
20             }
21         },
22         onLoad() {
23 
24         },
25         methods: {
26 
27         }
28     }
29 </script>
30 
31 <style>
32     .content {
33         display: flex;
34         flex-direction: column;
35         /* align-items: center; */
36         /* justify-content: center; */
37         background-image: url(../../static/img/bg.jpg);
38         background-position: center;
39         background-repeat: no-repeat;
40         background-size: cover;
41         height: 100%;
42         width: 100%;
43     }
44     .top{
45         height: 35%;
46         width: 100%;
47     }
48     .lottery{
49         /* position: absolute; */
50         /* top: 200rpx; */
51         /* bottom: 200rpx; */
52         margin: 2rpx;
53         width: 100%;
54         height: 700rpx;
55     }
56     .bottom{
57         position: absolute;
58         bottom: 10rpx;
59         color: #FFFFFF;
60         width: 100%;
61         text-align: center;
62     }
63 </style>
View Code

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

 1 <script>
 2     export default {
 3         onLaunch: function() {
 4             console.log('App Launch')
 5         },
 6         onShow: function() {
 7             console.log('App Show')
 8         },
 9         onHide: function() {
10             console.log('App Hide')
11         }
12     }
13 </script>
14 
15 <style>
16     /*每个页面公共css */
17     uni-page-body,#app {width:100%;height: 100%;}
18     page{
19         width: 100%;
20         height: 100%;
21     }
22 </style>
View Code

备注

八声甘州·对潇潇暮雨洒江天
【作者】柳永 【朝代】宋
对潇潇暮雨洒江天,一番洗清秋。
渐霜风凄紧,关河冷落,残照当楼。
是处红衰翠减,苒苒物华休。
惟有长江水,无语东流。
 
不忍登高临远,望故乡渺邈,归思难收。
叹年来踪迹,何事苦淹留?
想佳人、妆楼颙望,误几回、天际识归舟。
争知我,倚栏杆处,正恁凝愁。
posted @ 2020-11-21 23:58  老码识途呀  阅读(1249)  评论(0编辑  收藏  举报