讀古今文學網 > 微信公眾平台開發:從零基礎到ThinkPHP5高性能框架實踐 > 24.5.5 Ajax提交與轉盤控制 >

24.5.5 Ajax提交與轉盤控制

下面實現抽獎算法及中獎通知的功能。

首先定義指針轉動時中獎的角度和未中獎的角度,以便判斷用戶是否中獎,圖中有6個獎項,相應有6個未中獎區域。獎項角度及其他變量定義如下。


1 var totalAngle  = 0;
2 var steps = ;
3 var loseAngle = [36, 96, 156, 216, 276, 336];
4 var winAngle = [6, 66, 126, 186, 246, 306];
5 var prizeLevel;
6 var now = 0;
7 var count = 0;
8 var a = 0.01;
9 var outter, inner, timer, running = false;
  

用戶進入抽獎界面後,點擊抽獎指針,相應的代碼處理如下。


 1 $("#inner").click(function {
 2   if (running) return;
 3   if (count >= 3) {
 4     alert("達到最大抽獎次數!");
 5     return
 6   }
 7   $.ajax({
 8     url: "data.php",
 9     dataType: "json",
10     data: {
11       openid: "<?php echo $_GET["openid"];?>",
12       time: (new Date).valueOf
13     },
14     beforeSend: function {
15       running = true;
16       timer = setInterval(function {
17         i += 5
18       },
19       1)
20     },
21     success: function(data) {
22       // 達到最大抽獎次數
23       if (data.status == "MAX") {
24         alert("您已達到最大抽獎次數!");
25         count = 3;
26         clearInterval(timer);
27         return
28       }
29       // 有中獎時轉盤轉到相應位置
30       if (data.status == "WIN") {
31         $("#prizename").text(data.prizename);
32         count = 3;
33         clearInterval(timer);
34         prizeLevel = data.prizelevel;
35         start(winAngle[data.prizelevel - 1]);
36         return
37       }
38       // 未中獎則再給機會
39       running = false;
40       count++
41       prizeLevel = null;
42       start
43     },
44     // 未獲取JSON返回,前台處理
45     error: function {
46       prizeLevel = null;
47       start;
48       running = false;
49       count++
50     },
51     timeout: 4000
52   })
53 })
  

點擊事件發生時,頁面將向data.php文件發送POST請求,將當前用戶的OpenID和時間傳遞過去。data.php中在收到數據後將需要進行一系列的複雜處理,這些在24.5.6節中有詳細的講述下面是一個中獎情形的返回結果。


echo '{"status": "WIN", "prizename": "iPhone 5S", "prizelevel": "2"}';
  

該情形表示當前已中獎,獎品等級是2,獎品為iPhone 5S。data.php將該JSON數據返回給請求頁面,原頁面收到數據後,第29~37行代碼將進行處理,它將抽獎次數直接置為最大抽獎次數3,並且計算轉盤將要旋轉的角度,而這個旋轉角度也就是獎項的角度,以此確保轉盤停止後,指針落點無誤。

當中獎數據返回中沒有要中獎的標記(第38~42行)或者沒有接收到返回的JSON數據時(第44~50行),轉盤也需要計算旋轉角度,頁面將在前台累加抽獎次數,直到達到最大抽獎次數,然後提示用戶抽獎次數已經用完。如果返回的JSON數據中顯示已經達到最大抽獎次數,則以JSON數據優先作為判斷依據(第22~28行)。

當啟動轉盤轉動時,本次抽獎結果已經被旋轉角度確定下來了,這是通過start方法實現的。該方法帶有一個參數deg。如果中獎,則deg傳輸進來時就已經是某獎項的角度;如果沒有中獎,deg直接傳空,這時將隨機計算出一個非獎項的角度並賦給它。start方法的實現如下。


 1 function start(deg) {
 2     deg = deg || loseAngle[parseInt(loseAngle.length * Math.random)];
 3     running = true;
 4     clearInterval(timer);
 5     totalAngle  = 360 * 5 + deg;
 6     steps = ;
 7     now = 0;
 8     countSteps;
 9     requestAnimFrame(step)
  

在start函數中,需要根據旋轉角度生成本次轉動的步驟,這時往往需要添加N個360°,以便在旋轉N圈後落到真正的獎項區域。而這個旋轉角度以數組的方式保存。其角度差需要逐漸變小,以實現減速旋轉最終停下來的效果。該數組的生成代碼如下。


1 function countSteps {
2     var t = Math.sqrt(2 * totalAngle / a);
3     var v = a * t;
4     for (var i = 0; i < t; i++) {
5         steps.push((2 * v * i - a * i * i) / 2)
6     }
7     steps.push(totalAngle)
8 }
  

上面代碼將生成一個元素個數非常大的角度列表數組,數組存儲到steps中。這裡為了簡便,生成了一個簡化版本,如表24-9所示。

表24-9 旋轉角度數組

從表24-9中可以看到,轉盤將從0旋轉到624.9°,每一步的旋轉角度差將越來越小,直到為0,這時將停留到預先生成好的角度上。

而實現旋轉的動畫效果,是使用HTML5中的window.requestAnimFrame方法實現的,代碼如下。


 1 window.requestAnimFrame = (function {
 2   return window.requestAnimationFrame || 
 3          window.webkitRequestAnimationFrame || 
 4          window.mozRequestAnimationFrame || 
 5          window.oRequestAnimationFrame || 
 6          window.msRequestAnimationFrame ||
 7   function(callback) {
 8     window.setTimeout(callback, 1000 / 60)
 9   }
10 });
 

當動畫將每個旋轉角度走完以後,需要將中獎結果提示給用戶。沒有中獎時只需要彈出一個消息框即可,而中獎時需要隱藏轉盤、顯示中獎區域、顯示中獎結果。該部分代碼如下。


 1 function step {
 2     outter.style.webkitTransform = 'rotate(' + steps[now++] + 'deg)';
 3     outter.style.MozTransform = 'rotate(' + steps[now++] + 'deg)';
 4     outter.style.oTransform = 'rotate(' + steps[now++] + 'deg)';
 5     outter.style.msTransform = 'rotate(' + steps[now++] + 'deg)';
 6     if (now < steps.length) {
 7         requestAnimFrame(step)
 8     } else {
 9         running = false;
10         setTimeout(function {
11             if (prizeLevel != null) {
12                 var levelName= new Array("", "一等獎", "二等獎", "三等獎", "四等獎",
                   "五等獎", "六等獎")
13                 $("#prizelevel").text(levelName[prizeLevel]);
14                 $("#result").slideToggle(500);  // 顯示中獎區域
15                 $("#outercont").slideUp(500)    // 隱藏轉盤
16             } else {
17                 alert("親,繼續努力哦!")
18             }
19         },
20         200)
21     }
  

最終的中獎結果頁面如圖24-22所示。

圖24-22 大轉盤中獎頁面