
现代web表单通常利用html5内置的验证机制(如required、type="email"等)来提供基础的用户输入校验。然而,对于某些特定业务逻辑的验证,例如信用卡号的luhn算法校验,需要通过javascript进行自定义实现。核心挑战在于如何将这种自定义验证逻辑无缝地融入到现有的html5验证流程中,并确保当信用卡号不符合luhn算法时,能够像其他无效字段一样,正确地显示错误提示并阻止表单提交。
Luhn算法(也称为模10算法)是一种简单的校验和算法,常用于验证各种识别号码,如信用卡号、IMEI号等。它通过特定的计算规则,判断一串数字是否可能是有效号码,但它并不能验证号码的真实性或是否存在。
首先,我们需要一个独立的JavaScript函数来实现Luhn算法。这个函数接收一个字符串作为输入(通常是信用卡号),并返回一个布尔值,表示该号码是否通过Luhn校验。
/**
* 校验给定的字符串是否符合Luhn算法规则
* @param {string} value - 待校验的字符串(通常为信用卡号)
* @returns {boolean} - 如果符合Luhn算法返回true,否则返回false
*/
function checkLuhn(value) {
// 1. 移除所有非数字、非破折号、非空格字符。如果存在其他非数字字符,则直接视为无效。
if (/[^0-9-\s]+/.test(value)) return false;
// 2. 移除所有非数字字符,只保留数字进行Luhn算法计算
value = value.replace(/\D/g, "");
let nCheck = 0; // 校验和
let bEven = false; // 标记是否为偶数位(从右往左数,第一位为奇数位)
// 3. 从右向左遍历数字
for (let n = value.length - 1; n >= 0; n--) {
let cDigit = value.charAt(n);
let nDigit = parseInt(cDigit, 10);
// 4. 偶数位数字翻倍,如果大于9则减去9
if (bEven) {
if ((nDigit *= 2) > 9) {
nDigit -= 9;
}
}
// 5. 累加到校验和
nCheck += nDigit;
bEven = !bEven; // 切换奇偶位标记
}
// 6. 如果校验和能被10整除,则通过Luhn算法
return (nCheck % 10) === 0;
}Luhn算法原理简述:
为了将Luhn算法集成到现有表单的HTML5验证流程中,我们需要监听信用卡输入字段的input事件,并在每次输入时执行Luhn校验。关键在于使用HTMLElement.setCustomValidity()方法来控制字段的验证状态和自定义错误消息。
在表单初始化脚本中,添加对信用卡输入字段的事件监听:
(function () {
"use strict";
// ... 现有表单验证逻辑 ...
// 监听信用卡输入字段的输入事件
// 注意:这里使用了jQuery的on('input')方法
$('#cc').on('input', function() {
// 1. 获取信用卡输入字段的DOM元素
// 确保这里的选择器能够准确地获取到你的input元素。
// 在本例中,HTML结构是 <div id="cardContainer"><input id="cc" ...></div>
// 所以可以使用 document.querySelector('#cardContainer input') 或更直接的 document.getElementById('cc')
const field = document.getElementById('cc'); // 或者 document.querySelector('#cardContainer input');
// 2. 执行Luhn算法校验
if (checkLuhn($('#cc').val())) {
// 如果校验通过,清除自定义验证消息,使字段变为有效状态
field.setCustomValidity("");
} else {
// 如果校验失败,设置自定义验证消息,使字段变为无效状态
field.setCustomValidity("Invalid field."); // 这条消息将显示在浏览器默认的错误提示中
}
});
// ... 现有Luhn算法函数 checkLuhn ...
})();关键点解释:
为了确保setCustomValidity设置的错误消息能够被正确地显示,并且与现有的CSS样式协同工作,我们需要确保HTML结构中包含用于显示错误消息的元素,并且CSS样式能够响应字段的验证状态。
在信用卡输入字段的HTML部分,确保包含id属性,并且有empty-feedback和invalid-feedback的div:
<div class="flex mb-6 space-x-4">
<div id="cardContainer" class="w-full md:w-1/2">
<label for="cc" class="block mb-2 text-sm text-gray-600 dark:text-gray-400">Credit Card Number</label>
<input type="text" id="cc" placeholder="XXXX XXXX XXXX XXXX" required
class="w-full px-3 py-2 placeholder-gray-300 border-2 border-gray-200 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300" />
<div class="empty-feedback text-red-400 text-sm mt-1">
Please provide your credit card number.
</div>
<div class="invalid-feedback text-red-400 text-sm mt-1">
Please provide a valid credit card number.
</div>
</div>
</div>这里为信用卡输入字段的父容器添加了id="cardContainer",虽然在document.getElementById('cc')的情况下不是必需的,但如果你的选择器是document.querySelector('#cardContainer input'),则该ID是必要的。
确保以下CSS样式存在,它们负责根据表单的验证状态显示或隐藏错误消息:
.invalid-feedback,
.empty-feedback {
display: none; /* 默认隐藏错误消息 */
}
/* 当表单被标记为was-validated且输入框为空时,显示empty-feedback */
.was-validated :placeholder-shown:invalid ~ .empty-feedback {
display: block;
}
/* 当表单被标记为was-validated且输入框不为空但无效时,显示invalid-feedback */
.was-validated :not(:placeholder-shown):invalid ~ .invalid-feedback {
display: block;
}
/* 无效字段的边框样式 */
.is-invalid,
.was-validated :invalid {
border-color: #dc3545; /* 红色边框 */
}这些CSS规则利用了:invalid伪类和通用兄弟选择器(~)来根据字段的验证状态和是否为空来显示不同的错误提示。当setCustomValidity设置了错误消息时,浏览器会将该字段标记为:invalid。
以下是整合了Luhn算法验证的完整HTML、CSS和JavaScript代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>信用卡号Luhn算法表单验证</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.4/tailwind.min.css" rel="stylesheet"/>
<style>
/* 自定义验证反馈样式 */
.invalid-feedback,
.empty-feedback {
display: none;
}
.was-validated :placeholder-shown:invalid ~ .empty-feedback {
display: block;
}
.was-validated :not(:placeholder-shown):invalid ~ .invalid-feedback {
display: block;
}
.is-invalid,
.was-validated :invalid {
border-color: #dc3545;
}
</style>
</head>
<body class="flex items-center min-h-screen bg-gray-100 dark:bg-gray-900">
<div class="container mx-auto">
<div class="max-w-xl mx-auto my-10 bg-white p-5 rounded-md shadow-sm">
<div class="text-center">
<h1 class="my-3 text-3xl font-semibold text-gray-700 dark:text-gray-200">
联系我们
</h1>
<p class="text-gray-400 dark:text-gray-400">
填写以下表格发送消息。
</p>
</div>
<div class="m-7">
<form action="https://api.web3forms.com/submit" method="POST" id="form" class="needs-validation" novalidate>
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY_HERE" />
<input type="hidden" name="subject" value="New Submission from Web3Forms" />
<input type="checkbox" name="botcheck" id="" style="display: none;" />
<div class="flex mb-6 space-x-4">
<div class="w-full md:w-1/2">
<label for="first_name" class="block mb-2 text-sm text-gray-600 dark:text-gray-400">First Name</label>
<input type="text" name="name" id="first_name" placeholder="John" required
class="w-full px-3 py-2 placeholder-gray-300 border-2 border-gray-200 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300" />
<div class="empty-feedback invalid-feedback text-red-400 text-sm mt-1">
Please provide your first name.
</div>
</div>
</div>
<div class="flex mb-6 space-x-4">
<div class="w-full md:w-1/2">
<label for="email" class="block mb-2 text-sm text-gray-600 dark:text-gray-400">Email Address</label>
<input type="email" name="email" id="email" placeholder="email@example.com" required
class="w-full px-3 py-2 placeholder-gray-300 border-2 border-gray-200 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300" />
<div class="empty-feedback text-red-400 text-sm mt-1">
Please provide your email address.
</div>
<div class="invalid-feedback text-red-400 text-sm mt-1">
Please provide a valid email address.
</div>
</div>
</div>
<div class="flex mb-6 space-x-4">
<div id="cardContainer" class="w-full md:w-1/2">
<label for="cc" class="block mb-2 text-sm text-gray-600 dark:text-gray-400">Credit Card Number</label>
<input type="text" id="cc" placeholder="XXXX XXXX XXXX XXXX" required
class="w-full px-3 py-2 placeholder-gray-300 border-2 border-gray-200 rounded-md focus:outline-none focus:ring focus:ring-indigo-100 focus:border-indigo-300" />
<div class="empty-feedback text-red-400 text-sm mt-1">
Please provide your credit card number.
</div>
<div class="invalid-feedback text-red-400 text-sm mt-1">
Please provide a valid credit card number.
</div>
</div>
</div>
<div class="mb-6">
<button type="submit" class="w-full px-3 py-4 text-white bg-indigo-500 rounded-md focus:bg-indigo-600 focus:outline-none">
发送消息
</button>
</div>
<p class="text-base text-center text-gray-400" id="result"></p>
</form>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="main.js"></script> <!-- 引用你的JavaScript文件 -->
</body>
</html>(function () {
"use strict";
/*
* 表单验证初始化
*/
const forms = document.querySelectorAll(".needs-validation");
const result = document.getElementById("result");
Array.prototype.slice.call(forms).forEach(function (form) {
form.addEventListener(
"submit",
function (event) {
// 在提交前再次检查所有字段的有效性
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
// 将焦点设置到第一个无效字段
form.querySelectorAll(":invalid")[0].focus();
} else {
/*
* 使用fetch()进行表单提交
*/
const formData = new FormData(form);
event.preventDefault();
event.stopPropagation();
const object = {};
formData.forEach((value, key) => {
object[key] = value;
});
const json = JSON.stringify(object);
result.innerHTML = "请稍候...";
fetch("https://api.web3forms.com/submit", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: json
})
.then(async (response) => {
let jsonResponse = await response.json();
if (response.status === 200) {
result.innerHTML = jsonResponse.message;
result.classList.remove("text-gray-500");
result.classList.add("text-green-500");
} else {
console.error(response);
result.innerHTML = jsonResponse.message;
result.classList.remove("text-gray-500");
result.classList.add("text-red-500");
}
})
.catch((error) => {
console.error(error);
result.innerHTML = "发生了一些错误!";
})
.then(function () {
form.reset();
form.classList.remove("was-validated");
setTimeout(() => {
result.style.display = "none";
}, 5000);
});
}
form.classList.add("was-validated"); // 标记表单为已验证,触发CSS显示错误
},
false
);
});
// 信用卡输入字段的Luhn算法验证
$('#cc').on('input', function(){
// 获取信用卡输入字段的DOM元素
const field = document.getElementById('cc'); // 或者 document.querySelector('#cardContainer input');
const inputValue = $(this).val(); // 获取当前输入值
if (checkLuhn(inputValue)) {
field.setCustomValidity(""); // 校验通过,清除自定义错误
} else {
field.setCustomValidity("Invalid field."); // 校验失败,设置自定义错误
}
});
/**
* Luhn算法校验函数
* @param {string} value - 待校验的字符串
* @returns {boolean} - 如果符合Luhn算法返回true,否则返回false
*/
function checkLuhn(value) {
// 接受只包含数字、破折号或空格的字符串
if (/[^0-9-\s]+/.test(value)) return false;
// 移除所有非数字字符
value = value.replace(/\D/g, "");
let nCheck = 0, bEven = false;
for (let n = value.length - 1; n >= 0; n--) {
let cDigit = value.charAt(n);
let nDigit = parseInt(cDigit, 10);
if (bEven) {
if ((nDigit *= 2) > 9) nDigit -= 9;
}
nCheck += nDigit;
bEven = !bEven;
}
return (nCheck % 10) === 0;
}
})();通过将Luhn算法封装为独立的JavaScript函数,并结合HTMLElement.setCustomValidity() API,我们可以有效地将自定义验证逻辑
以上就是整合Luhn算法实现信用卡号表单验证的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号