假设我们正在编写一个注册的页面,在点击注册按钮之前,有如下几条校验逻辑。
- 用户名不能为空。
- 密码长度不能少于 6 位。
- 手机号码必须符合格式。
<form action="http:// xxx.com/register" id="registerForm" method="post">
<div>请输入用户名:<input type="text" name="userName" /></div>
<div>请输入密码:<input type="text" name="password" /></div>
<div>请输入手机号码:<input type="text" name="phoneNumber" /></div>
<button>提交</button>
</form>
html 的部分很简单,主要想想提交里怎么写?
来,简单构思下~
来,简单构思下~
来,简单构思下~
凭直觉写的表单校验 - v1
let form = document.querySelector("#registerForm");
form.onsubmit = () => {
if (form.userName.value === "") {
alert("用户名不能为空");
return false;
}
if (form.password.value.length < 6) {
alert("密码不能少于6位");
return false;
}
if (!/[0-9]{11,11}/.test(form.phoneNumber.value)) {
alert("手机号码格式不正确");
return false;
}
};
一顿操作猛如虎,好,写完之后,看看代码有何不妥:
- registerForm.onsubmit 函数比较庞大,包含了很多 if-else 语句,这些语句需要覆盖所有 的校验规则。
- registerForm.onsubmit 函数缺乏弹性,如果增加了一种新的校验规则,或者想把密码的长 度校验从 6 改成 8,我们都必须深入 registerForm.onsubmit 函数的内部实现,这是违反开 放—封闭原则的。
- 算法的复用性差,如果在程序中增加了另外一个表单,这个表单也需要进行一些类似的 校验,那我们很可能将这些校验逻辑复制得漫天遍野。
联系之前说过的策略模式,来改进代码~
改进版的表单校验 - v2
// 将算法的实现单独封装起来
var strategies = {
isNonEmpty: function(value, errorMsg) {
// 不为空
if (value === "") {
return errorMsg;
}
},
// 这里把length作为参数
minLength: function(value, length, errorMsg) {
// 限制最小长度
if (value.length < length) {
return errorMsg;
}
},
isMobile: function(value, errorMsg) {
// 手机号码格式
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg;
}
}
};
// 算法的使用
let form = document.querySelector("#registerForm");
form.onsubmit = function() {
var errorMsg = "用户名不能为空";
if ((strategies.isNonEmpty(registerForm.userName.value), errorMsg)) {
alert(errorMsg);
return false;
}
var errorMsg = "密码长度不能少于6 位";
if ((strategies.minLength(registerForm.password.value), 6, errorMsg)) {
alert(errorMsg);
return false;
}
var errorMsg = "手机号码格式不正确";
if ((strategies.isMobile(registerForm.phoneNumber.value), errorMsg)) {
alert(errorMsg);
return false;
}
// 这里开始ajax请求。。。
};
写完之后,我屮艸芔茻!!!这好像和第一版也没什么大的区别。看起来一点也不优雅!!!
但这里提供了关键性思路,提交部分明显就是重复,很容易想到列表循环,这里将其抽象成 validator 的类。
也就是 validator 类提供 add 和 start,,add 负责将每种校验方式放进一个数组,start 负责遍历数组,一旦有返回值直接返回且终止返回。
。。。咳咳,有点难度,可以试试写写。
初见美好 - v3
// var strategies = 、、、
class Validator {
constructor() {
this.cache = [];
}
add(dom, rule, msg) {
// 把单个验证表单的fn存下来
let [strategy, length] = rule.split(":");
let params = length ? [dom.value, length, msg] : [dom.value, msg];
console.log(params);
let fn = () => {
return strategies[strategy](...params);
};
this.cache.push(fn);
}
start() {
for (var i = 0; i < this.cache.length; i++) {
let errMsg = this.cache[i]();
if (errMsg) {
return errMsg;
}
}
}
}
// 应用
let form = document.querySelector("#registerForm");
function validateData() {
let validator = new Validator();
validator.add(form.userName, "isNonEmpty", "用户名不能为空");
validator.add(form.password, "minLength:6", "密码不能少于6位");
validator.add(form.phoneNumber, "isMobile", "手机号码格式不正确");
// 需要加新的校验规则,直接添加这里就好
let errMsg = validator.start();
return errMsg;
}
// submit里面就很优雅了
form.onsubmit = () => {
let errMsg = validateData();
if (errMsg) {
alert(errMsg);
return false;
}
};
写完这些之后,很赞啦!
但。。。还有点点缺点,比如用户名想同时验证其为空和长度的话,需要单个列出,显然又累赘了
接下来试着将其改成validator.add(form.userName, {isNonEmpty:'用户名不能为空','minLength:6':'用户名长度不能少于6位'})
validator.add(form.userName, "isNonEmpty", "用户名不能为空");
validator.add(form.userName, "minLength:6", "用户名长度不能少于6位");
相知相识 - v4
// var strategies = 。。。;
class Validator {
constructor() {
this.cache = [];
}
// 没事原先的add提取出来
_handleRule(dom, rule, msg) {
// 把单个验证表单的fn存下来
let [strategy, length] = rule.split(":");
let params = length ? [dom.value, length, msg] : [dom.value, msg];
console.log(params);
let fn = () => {
return strategies[strategy](...params);
};
this.cache.push(fn);
}
add(dom, rules) {
rules.forEach(item => {
for (let rule in item) {
let msg = item[rule];
// 遍历的时候,直接使用就好
this._handleRule(dom, rule, msg);
}
});
}
start() {
for (var i = 0; i < this.cache.length; i++) {
let errMsg = this.cache[i]();
if (errMsg) {
return errMsg;
}
}
}
}
// 应用
let form = document.querySelector("#registerForm");
function validateData() {
let validator = new Validator();
validator.add(form.userName, [
{ isNonEmpty: "用户名不能为空" },
{ "minLength:6": "用户名不能少于6位" }
]);
validator.add(form.password, [{ "minLength:6": "密码不能少于6位" }]);
validator.add(form.phoneNumber, [{ isMobile: "手机号码格式不正确" }]);
console.log(validator);
let errMsg = validator.start();
return errMsg;
}
form.onsubmit = () => {
let errMsg = validateData();
if (errMsg) {
alert(errMsg);
return false;
}
};
完结,下次看表单验证的一些插件可能就能加深理解了!
引用
这里的案例是《JavaScript的设计模式与开发实践》里面的,写的非常好,强烈安利!!!
对了之前写了个策略模式的入门