項目需求運用到大轉盤 可設置概率 可直接自定義結果 效果如下
兩種方法及結合法
一 通過canvas 實現 但是因為定時器原因 手機端卡頓嚴重 故而最終使用了方法二 但也是該記錄下 學習canvas
二 通過小程序Api animation完成完美解決卡頓問題 更精確定位 有樣式缺陷 css無法解決樣式 自動分配問題 故結合一二兩種方法 出現第三種
三 通過小程序Api animation 做動畫旋轉 樣式用canvas來實現 完美解決各類問題
話不多說踩坑部分 就不展示 直接上第三種方法
創建動畫區域 (animation) 動畫可參考小程序官方API animationData動畫參數 在點擊開始的時候填充數據
<view class="wrapper-content" style='margin:0 auto;'> <view class="canvas-container"> <view animation="{{animationData}}" class="canvas-content" style='margin:0 auto;'> </view> </view> </view>
//CSS
.wrapper-content{ background: #E0CFBC; border-radius: 50%; width: 720rpx; height: 720rpx; padding: 40rpx; position: relative; box-sizing: border-box; z-index: 101; } .canvas-container { margin: 0 auto; position: absolute; left: 40rpx; top: 40rpx; width: 640rpx; height: 640rpx; border-radius: 50%; } .canvas-content { overflow: hidden; box-sizing: content-box; border: 20rpx solid #CDB193; position: absolute; left: 0; top: 0; z-index: 1; display: block; width: 600rpx; height: 600rpx; border-radius: inherit; background-clip: padding-box; }
配合CSS3 扇形實現圓盤
html
<!-- 扇形 --> <view class="canvas-list"> <view class="canvas-item2" wx:for="{{awardsConfig.slicePrizes}}" wx:key="key" style="transform: rotate({{item.item2Deg}});background-color:{{awardsConfig.slicePrizes.length==2?(index%2==0?'#faf5e7':'#f3e2c6'):''}};opacity:{{ awardsConfig.slicePrizes.length==2?item.opacity: awardsConfig.slicePrizes.length==3?item.opacity:''}};width:{{size}}rpx;height:{{size/2-2}}rpx;transform-origin:{{size/2}}rpx {{size/2}}rpx"> <view class="canvas-item2-after" style="transform: rotate({{item.afterDeg}});background-color:{{index%2==0?'#faf5e7':'#f3e2c6'}};opacity:{{ awardsConfig.slicePrizes.length==3?'':item.opacity}};width:{{size/2}}rpx;height:{{size/2}}rpx;transform-origin: {{size/2}}rpx {{size/2}}rpx"> </view> <view wx:if='{{awardsConfig.slicePrizes.length==3}}' class="canvas-item2-after" style="background-color:{{index%2==0?'#faf5e7':'#f3e2c6'}};width:{{size/2}}rpx;height:{{size/2}}rpx;transform-origin: {{size/2}}rpx {{size/2}}rpx"></view> </view> </view> <!-- 選項內容 --> <view class="wk-wheel-list"> <view class="wk-wheel-item" data-index="{{index}}" wx:for="{{awardsConfig.slicePrizes}}" wx:key='key'> <view class="wk-wheel-icontent" style="height:262rpx;overflow:hidden;font-size:{{item.text.length>9?'20':'26'}}rpx;padding-top:5rpx;transform: rotate({{index*turnNum}}turn);transform-origin: 50% {{size/2-2}}rpx"> <view class="canvas-litem-text-name">{{item.text}}</view> <view class="canvas-litem-text-image"> <image src="{{item.img}}" mode="widthFix" style="width:80rpx;max-height:60rpx;padding:10rpx 0 0;"></image> <view class="canvas-litem-text-image-num">100</view> </view> <view style="font-size:20rpx;">{{item.num}}x1</view> </view> </view> </view> </view>
CSS
/* //css扇形 */ .canvas-item2 { position: absolute; left: 0px; top: 0; width: 620rpx; height: 328rpx; color: #e4370e; font-weight: bold; transform-origin: 330rpx 330rpx; overflow: hidden; } .canvas-item2-after { position: absolute; top: 0; left: 0; width: 330rpx; height: 330rpx; transform-origin: 330rpx 330rpx; opacity: 1; } .wk-wheel-list { position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 9; } .wk-wheel-item { position: absolute; left: 0; top: 0; width: 100%; height: 100%; color: #fff; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.6); } .wk-wheel-icontent { position: relative; display: block; padding-top: 50rpx; margin: 0 auto; text-align: center; transform-origin: 50% 328rpx; color: #AA8B6B; }
1.awardsConfig.slicePrizes為獎品列表 因為大轉盤是圓的 所以W H 是一樣的
2.this.data.windowWidth 是屏幕的寬度 小程序有API 可以獲取 用屏幕寬度/750*設置內容寬度rpx = 實際內容寬度的px 值
3.size 是圓盤的寬度
設置點擊抽獎按鈕 兩種方法 一直接在canvas內繪制 二在HTML里面通過定位實現
提供二 HTML 定位實現按鈕
<view class="canvas-btn" bindtap="getLottery"> <view> <view style="font-size:56rpx;color:#fff;padding-bottom:4rpx;">開始</view> <view style="font-size:20rpx;color:#6F5942;font-weight:600;">點擊抽獎</view> </view> </view>
css
.canvas-btn { display: flex; flex-direction: column; justify-content: space-around; position: absolute; left: 50%; top: 50%; margin-left: -110rpx; margin-top: -110rpx; z-index: 400; width: 220rpx; height: 220rpx; border-radius: 50%; color: #f4e9cc; border: 10px solid #cdb193; text-align: center; font-size: 40rpx; text-decoration: none; box-sizing: border-box; } .canvas-btn>view { position: absolute; top: 7%; left: 7%; width: 86%; height: 86%; border-radius: 50%; box-sizing: border-box; padding: 22rpx 20rpx 0; background: linear-gradient(134deg, rgba(232, 219, 197, 1) 0%, rgba(205, 177, 147, 1) 100%); /* box-shadow:0px 5px 7px 0px rgba(255,255,255,1); */ margin: auto; z-index: 102; } .canvas-btn::after { position: absolute; display: block; content: ' '; left: 39%; top: -78%; width: 0; height: 0; overflow: hidden; border-width: 80rpx 20rpx 80rpx 20rpx; border-style: solid; border-color: transparent; border-bottom-color: #ffab52; }
js
getLottery() { let that = this; // 獲取獎品配置 let awardsConfig = that.data.awardsConfig, runNum = 12, len = awardsConfig.slicePrizes.length, awardIndex = 0; awardIndex = parseInt(Math.random() * 6) console.log("獎品序號:" + awardIndex); // 旋轉抽獎 app.runDegs = app.runDegs || 0 app.runDegs = app.runDegs + (360 - app.runDegs % 360) + (360 * runNum - awardIndex * (360 / len)) //創建動畫 let animationRun = wx.createAnimation({ duration: 4000, timingFunction: 'ease' }) console.log(awardsConfig.slicePrizes[awardIndex]); that.animationRun = animationRun animationRun.rotate(app.runDegs - (360 / len * 2 + (360 / len)) ).step() that.setData({ animationData: animationRun.export() }) },
點擊按鈕觸發getLottery 進行動畫數據填充 實現旋轉效果 runNum為旋轉的圈數 awardIndex為中獎的序號
整體如此完美實現獻上整體代碼
html
<view class="wrapper-content" style='margin:0 auto;'> <view class="canvas-container-quiu" wx:for="{{list}}" style="-webkit-transform: rotate({{index * (360/list.length)}}deg);transform: rotate({{index * (360/list.length)}}deg);{{index%2==0?'background:#F2E86D':'background:#ffffff'}}"></view> <view class="canvas-container"> <view animation="{{animationData}}" class="canvas-content" style='margin:0 auto;'> <canvas class="canvas-line" disable-scroll="true" bindtouchstart="canvasTouchStart" bindtouchmove="touchMove" bindtouchend="canvasTouchEnd" canvas-id="canvas"></canvas> </view> <view class="canvas-btn" bindtap="getLottery"> <view> <view style="font-size:56rpx;color:#fff;padding-bottom:4rpx;">開始</view> <view style="font-size:20rpx;color:#6F5942;font-weight:600;">點擊抽獎</view> </view> </view> </view> </view>
css
.wrapper-content{ background: #E0CFBC; border-radius: 50%; width: 720rpx; height: 720rpx; padding: 40rpx; position: relative; box-sizing: border-box; z-index: 101; } .canvas-container ul, .canvas-container li { margin: 0; padding: 0; list-style: none; } .canvas-container { margin: 0 auto; position: absolute; left: 40rpx; top: 40rpx; width: 640rpx; height: 640rpx; border-radius: 50%; } .canvas-container-quiu{ width: 20rpx; height: 20rpx; border-radius: 50%; position: absolute; left:10rpx; top: 50%; margin-top: -8rpx; -webkit-transform-origin: 330rpx 50%; transform-origin: 350rpx 50%; z-index: 1001; } .canvas-content { overflow: hidden; box-sizing: content-box; border: 20rpx solid #CDB193; position: absolute; left: 0; top: 0; z-index: 1; display: block; width: 600rpx; height: 600rpx; border-radius: inherit; background-clip: padding-box; } .canvas-btn { display: flex; flex-direction: column; justify-content: space-around; position: absolute; left: 50%; top: 50%; margin-left: -110rpx; margin-top: -110rpx; z-index: 400; width: 220rpx; height: 220rpx; border-radius: 50%; color: #f4e9cc; border: 10px solid #cdb193; text-align: center; font-size: 40rpx; text-decoration: none; box-sizing: border-box; } .canvas-btn>view { position: absolute; top: 7%; left: 7%; width: 86%; height: 86%; border-radius: 50%; box-sizing: border-box; padding: 22rpx 20rpx 0; background: linear-gradient(134deg, rgba(232, 219, 197, 1) 0%, rgba(205, 177, 147, 1) 100%); /* box-shadow:0px 5px 7px 0px rgba(255,255,255,1); */ margin: auto; z-index: 102; } .canvas-btn::after { position: absolute; display: block; content: ' '; left: 39%; top: -78%; width: 0; height: 0; overflow: hidden; border-width: 80rpx 20rpx 80rpx 20rpx; border-style: solid; border-color: transparent; border-bottom-color: #ffab52; }
js
var app = getApp() var utils = require('../../utils/utils.js'); var Animation = require('../../utils/Animation.js'); var Wheel = require('../../utils/Wheel.js'); Page({ /** * 頁面的初始數據 */ data: { awardsList: {}, list: [], statusBarHeight: getApp().globalData.statusBarHeight, scrollHeight: 200, windowWidth:0, windowHeight:0, awardsConfig: { count: 50, slicePrizes: [ { text: "恭喜中大獎", img: "/assets/coupon_gold.png", title: "積分券x1", num: "1200", x: "1" }, { text: "醫療服務費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "50", x: "2" }, { text: "健康保養費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "500", x: "1" }, { text: "謝謝參與", img: "/assets/coupon_gold.png", title: "積分券x3", num: "0", x: "2" }, { text: "青春補償費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "200", x: "1" }, { text: "感恩奉獻費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "100", x: "2" }, { text: "咨詢售后費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "150", x: "1" }, { text: "謝謝參與", img: "/assets/coupon_gold.png", title: "積分券x1", num: "0", x: "1" }, { text: "咨詢售后費", img: "/assets/coupon_gold.png", title: "積分券x1", num: "150", x: "1" }, { text: "謝謝參與", img: "/assets/coupon_gold.png", title: "積分券x1", num: "0", x: "1" } ], }, }, /** * 生命周期函數--監聽頁面加載 */ onLoad: function(options) { var that = this; that.initAdards() wx.getSystemInfo({ success: function (res) { that.setData({ windowWidth: res.windowWidth, windowHeight: res.windowHeight, scrollHeight: res.windowHeight - res.windowWidth / 750 * (getApp().globalData.statusBarHeight * 2 + 98) }); }, }) }, onReady: function(e) { let that = this, fps = 60, awardsConfig = that.data.awardsConfig, w = this.data.windowWidth / 750 * 600, h = this.data.windowWidth / 750 * 600, ; wx.getSystemInfo({ success: function(res) { that.setData({ contentHeight: res.windowHeight }); }, }) that.setData({ count: awardsConfig.count }) let len = awardsConfig.slicePrizes.length, rotateDeg = 360 / len / 2 , list = [], turnNum = 1 / len; for (var i = 0; i < len; i++) { list.push({ award: awardsConfig.slicePrizes[i].text, }); }; that.setData({ list: list.concat(list) }); }, //初始化獎品數據 計算角度 initAdards() { var that = this, awardsConfig = that.data.awardsConfig; var t = awardsConfig.slicePrizes.length; // 選項長度 var e = 1 / t, i = 360 / t, r = i - 90; for (var g = 0; g < t; g++) { awardsConfig.slicePrizes[g].item2Deg = g * i + 90 - i / 2 + "deg"; //當前下標 * 360/長度 + 90 - 360/長度/2 awardsConfig.slicePrizes[g].afterDeg = r + "deg"; awardsConfig.slicePrizes[g].opacity = '1'; } that.setData({ turnNum: e, // 頁面的單位是turn awardsConfig: awardsConfig, }) }, /** * 抽獎處理函數: */ getLottery: function () { let that = this; // 獲取獎品配置 let awardsConfig = that.data.awardsConfig, runNum = 12, len = awardsConfig.slicePrizes.length, awardIndex = 0; awardIndex = parseInt(Math.random() * 6) console.log("獎品序號:" + awardIndex); // 旋轉抽獎 app.runDegs = app.runDegs || 0 app.runDegs = app.runDegs + (360 - app.runDegs % 360) + (360 * runNum - awardIndex * (360 / len)) //創建動畫 let animationRun = wx.createAnimation({ duration: 4000, timingFunction: 'ease' }) console.log(awardsConfig.slicePrizes[awardIndex]); that.animationRun = animationRun animationRun.rotate(app.runDegs).step() that.setData({ animationData: animationRun.export() }) }, })