前期內容提要:
- 【抽獎平臺開發(1)】抽獎功能的前端實現(HTML+JS+CSS)
在實現抽獎功能的前端搭建後,這一章主要目標是將抽獎結果通過表單方式提交至後端。
基本思路:與一般接受用戶輸入內容後形成表單提交後端不同的是,這裏需要提交至後端的是用戶的抽獎結果,這個數據不是由用戶手動輸入生成的而是JS運算產生的結果。而表單提交的數據應當是<input>
標籤內的value
值,這就需要將抽獎結果轉化爲一個value
值傳入表單中的一個<input>
標籤內。
具體而言,如上圖所示,在表單內創建一個用於接受數據的<input>
標籤,value
值爲空,等待傳值;將抽獎結果
通過console.log打印至控制檯
,然後將控制檯上的結果傳至一個<div>
標籤裏去,最後將<div>
標籤裏的抽獎結果傳至<input>
標籤的value
內,觸發提交事件後,提交表單至後端。
一、創建數據容器並存儲數據結果
1. 創建數據容器
一方面是需要創建一個接受控制檯打印結果的<div>
標籤(Id=info
),另一方面是表單內創建一個用於接受數據的<input>
標籤(Id=results
):其中<input>
標籤中定義name
屬性用於後端定位接受表單數據中的哪一個具體標籤;Id
屬性作爲標籤的唯一標識符用於<div>
標籤(Id=info
)定位<input>
標籤,向其value
賦值。
<div id="info" style="display:none;"></div>
<form id='test_form' action="gift.php" method="get">
<input name="results" id="results" type="hidden" value="">
</form>
2. 將控制檯信息傳輸並存儲至<div>
標籤(Id=info
)
<script>
var infoConsole = document.getElementById('info');
if (infoConsole) {
if (console) {
var _consolee = {
log:console.log
}
console.log = function(attr){
_consolee.log(attr);
var str = JSON.stringify(attr, null, 4);
var node = document.createElement("h1");
var textnode = document.createTextNode(str);
node.setAttribute("type","text");
node.appendChild(textnode);
infoConsole.appendChild(node);
}
}
function show(){
var type = infoConsole.getAttribute("type");
if (type === "0") {
infoConsole.style.cssText = "width:100vw;height:40vh;";
infoConsole.setAttribute("type","1");
}else{
infoConsole.removeAttribute('style');
infoConsole.setAttribute("type","0");
}
}
}
</script>
當<div>
標籤(Id=info
)接受到控制檯
打印結果後,會自動創建<h1>
子標籤存儲抽獎數據。
二、向表單內<input>
標籤中的value賦值
我們需要將<div>
標籤(Id=info
)在接受到控制檯
傳輸結果後自動創建的用於存儲結果的<h1>
子標籤內容傳至表單內用於接受數據的<input>
標籤內的value
屬性中,以作爲表單內容予以提交。
<script>
function tijiao(){
var obox = document.getElementById("info");
aa = obox.firstElementChild.innerHTML;
var input = document.getElementById("results");
input.value=aa;
}
</script>
值得一提的是,在這裏我僅選擇了
<div>
標籤(Id=info
)下第一個子標籤數值予以傳輸,其目的是爲了防止數據庫被惡意抽獎結果大量寫入,當然我們可以不限定在第一個子標籤內傳值,但是需要注意原生JS在獲取子標籤時空格也會被捕獲,可以嘗試使用jQuery實現需求。
三、提交表單
表單需要在抽獎結果生成後才能被提交,因此提交表單的步驟可以放至start()
函數中去,具體而言通過var form
的方式定位表單的Id:test_form
,使用form.submit()
提交表單內容:
<script>
function start(){
var initial=getArrayItems(ArrList,1);
var form = document.getElementById('test_form');
for (var i = 0; i < initial; i++) {
setTimeout(()=>{
$('.gift').removeClass("selected");
gift=$('.gift:eq('+ position[(x%8)] +')');
gift.addClass('selected');
x++;
if (x==initial) {setTimeout(()=>{
if (position[(x%8)]==2) {
randmoney();
}else{
alert('恭喜獲得禮物:'+gift.text());
}
setTimeout(function(){console.log(gift.text());tijiao();form.submit();},1999);
x=0;
},10)}
},i*150);
}
}
</script>
可以看到,在點擊抽獎按鈕後,開始執行start()
函數,產生抽獎結果後,先彈窗通知結果(alert('恭喜獲得禮物:'+gift.text())
),之後將結果打印至控制檯(console.log(gift.text())
),此後控制檯
打印結果會傳輸至<div>
標籤(Id=info
)的<h1>
子標籤,之後將執行tijiao()
函數將<h1>
子標籤存儲結果傳至表單下<input>
標籤中的value
屬性中去,最後執行form.submit()
提交表單。
注意:值得留意的是,由於
tijiao()
函數只傳輸控制檯第一條打印結果至表單下的<input>
標籤中去,這裏把將抽獎結果打印至控制檯系列命令
封裝在了一個延遲執行語句裏,其目的在於保證當抽獎結果是隨機紅包時,控制檯第一條打印結果是隨機紅包的具體數額
而非隨機金額紅包
這行文字。
此外,正是由於tijiao()
函數只傳輸控制檯第一條打印結果至表單下的<input>
標籤中去(防止數據庫被惡意抽獎結果大量寫入)這一邏輯,因此抽獎頁面在未刷新控制檯內打印內容時,應當且只應當允許用戶執行一次抽獎命令。這就需要爲抽獎函數添加一個定時器,用於限制用戶的抽獎次數,同時限制用戶在短時間內重複惡意點擊抽獎按鈕觸發抽獎函數。
var repeat = 2;
function time(){
var timer = setInterval(function() {
if (repeat == 2) {
repeat--;
start();
document.getElementById('btn1').style.backgroundColor ="#787878";
document.getElementById('btn1').disabled=true;
setTimeout(function (){
document.getElementById('btn1').disabled=false;
},5000);
}else if (repeat == 1) {
setTimeout("repeat--","1000");
clearInterval(timer);
} else {
clearInterval(timer);
alert('已沒有剩餘抽獎機會');
}
}, 1000);
}
我要禮物
按鈕調用函數也需要從原來的start()
函數變爲現在的time()
函數
<button class="start" onclick="time()">我要禮物</button>
在初始情況下,用戶點擊我要禮物
按鈕,將執行定時器,定時器檢測到repeat = 2
,將執行一次start()
函數,此時按鈕顏色變灰(外觀上提示用戶不要再點擊),並凍結按鈕在執行抽獎函數過程中的觸發(邏輯上阻止用戶在抽獎中重複點擊按鈕造成的抽獎函數的多次觸發),同時repeat
值變成1,在1秒後repeat
值歸零後退出循環,當按鈕點擊事件解凍後,用戶再次點擊我要禮物
按鈕,將不再執行start()
函數,彈出警告已沒有剩餘抽獎機會
。除非刷新頁面(刷新頁面後:控制檯內打印內容
被清空,repeat
值重新變爲2
,符合抽獎邏輯,允許抽獎)。
這裏講講定時器設計過程中基於幾個邏輯問題產生的版本更迭:
- 第一次抽獎時不應彈出警告。
//第一版
var repeat = 1;
function time(){
var timer = setInterval(function() {
if (repeat == 0) {
clearInterval(timer);
alert('已沒有剩餘抽獎機會');
} else {
start();
repeat--;
}
}, 1000);
}
這是設計之初 第一版本 的定時器邏輯,後經測試發現,在執行start()
函數時repeat
值歸零,由於計時器1秒鐘重複執行一次,因此在執行start()
函數(經測試需要5秒執行完畢)的同時會再次觸發執行repeat== 0
情形下的彈出警告
的操作,顯然第一次抽獎過程不應當彈出警告
框。故將第一次判斷和警告框判斷分離,以解決上述問題,方案如下:
//第二版
var repeat = 2;
function time(){
var timer = setInterval(function() {
if (repeat == 0) {
clearInterval(timer);
alert('已沒有剩餘抽獎機會');
}else if (repeat == 2) {
start();
repeat--;
else {
setTimeout("repeat--","1000");
clearInterval(timer);
}
}, 1000);
}
- 解決用戶在短時間內重複惡意點擊抽獎按鈕觸發抽獎函數後由於不可預測
repeat
值而導致警告
框無法彈出的問題。
根據第一版本改動後的 第二版本 定時器邏輯,經測試發現的問題是,當用戶在短時間內重複惡意點擊抽獎按鈕觸發抽獎函數後會多次執行repeat--
,致使repeat
在自減後不一定恆爲 0
,又由於只有在repeat == 0
的情況下才能彈出警告
框,因此當出現用戶惡意點擊情形下,警告
框將無法正常彈出。基於上述問題調整了判斷邏輯,做出如下優化:
//第三版
var repeat = 2;
function time(){
var timer = setInterval(function() {
if (repeat == 2) {
repeat--;
start();
}else if (repeat == 1) {
setTimeout("repeat--","1000");
clearInterval(timer);
} else {
clearInterval(timer);
alert('已沒有剩餘抽獎機會');
}
}, 1000);
}
- 很顯然,即使使用 第三版本 的定時器邏輯,也只能保證“警告框”能夠正常彈出,並不能阻止用戶在短時間內重複惡意點擊抽獎按鈕行爲,抽獎函數被重複觸發的現實也沒有真正意義上得到解決。因此在最後版的改進中,凍結了按鈕在執行抽獎函數過程中的觸發可能性,以徹底解決上述問題。
//第四版將按鍵id命名爲btn1,並新增按鈕凍結功能。
document.getElementById('btn1').style.backgroundColor ="#787878";
document.getElementById('btn1').disabled=true;
setTimeout(function (){
document.getElementById('btn1').disabled=false;
},5000);
四、後端PHP接收數據
- 前端通過表單的形式向後端gift.php提交數據
一般情況下用 JS 或 jQuery 的 submit 方法提交 form 表單是不會被瀏覽器攔截的,但是異步的情況下用 js 提交 form 表單就會被瀏覽器攔截,因此如果給表單設置了target="_blank"
,由於URL新窗口並非用戶的實時點擊而是在執行start()
函數提交表單後彈出,會被瀏覽器認定爲惡意彈窗而攔截,致使無法正常提交數據至後端,需要特別注意。
<form id='test_form' action="gift.php" method="get">
<input name="results" id="results" type="hidden" value="">
</form>
此外,在抽獎完成後,數據的後端提交無需回顯至用戶界面,也不應當允許頁面自動跳轉覆蓋原來的抽獎頁面。基於此,在表單HTML部分,做出如下修改:
<form id='test_form' action="gift.php" method="get" target="frameName">
<input name="results" id="results" type="hidden" value="">
</form>
<iframe src="" frameborder="0" name="frameName" style="display:none;"></iframe>
- 後端gift.php接收前端提交過來的數據
後端獲取表單中name
名爲results
的標籤的value
值,即表單內用於接受數據的<input>
標籤內的value
值,即抽獎結果。
<html>
<body>
Gift lists: <?php echo $_GET["results"]. "<br>"; ?>
</body>
</html>
- 上線測試:
至此,我們成功將抽獎結果通過表單的方式提交至了後端(源碼已上傳),下一章將記錄如何將抽獎結果提交的表單上傳至數據庫,完成抽獎平臺前臺的全部開發。
後期內容提要:
- 【抽獎平臺開發(3)】將抽獎結果提交的表單上傳至數據庫,完成抽獎平臺前臺開發(PHP+MySQL)
- 【抽獎平臺開發(4)】基於MVC模式實現數據後臺管理操作的可視化(PHP+HTML+MySQL)
如果您有任何疑問或者好的建議,期待你的留言與評論!