前期内容提要:
- 【抽奖平台开发(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)
如果您有任何疑问或者好的建议,期待你的留言与评论!