You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

204 lines
6.0 KiB

/**
* H5表单验证 适用所有,当同时存在多个逻辑时 有先后顺序
* 注意:凡是设置了正则表达式验证的 需在后面指出具体规则以告知用户
* @author lautin
* @created 2019-11-22 14:14:20
*/
class Validate {
// 初始化验证元素
constructor(root) {
// 提取表单中的输入控件
if (!root.nodeType) root = document.querySelector(root);
// 将nodeList以及标识符 写入全局对象中
Object.assign(this, {
flag: true,
}, {
fields: this.extractInputs(root),
});
}
/**
* 遍历节点 提取输入控件
* @param {dom}} node
* @param {nodeList} result 返回DOM集合对象
*/
extractInputs(node, result = null) {
let fields = result || [];
const types = ["text", "password", "file", "number", "range", "search", "email", "url"];
for (let x = node.firstChild; x != null; x = x.nextSibling) {
// 如果是元素节点 则检测节点名称并递归
if (x.nodeType == node.ELEMENT_NODE) {
switch (x.nodeName.toLowerCase()) {
case "input":
if (types.includes(x.type)) {
if (getComputedStyle(x, false).display != "none") {
fields.push(x); //放入该节点
}
}
break;
case "select":
case "textarea":
fields.push(x); //放入该节点
break;
}
// 继续递归
this.extractInputs(x, fields);
}
}
return fields;
}
/**
* text验证maxLength和minLength
* @param {object} state
* @param {dom} item
*/
textTask(state, item) {
let result = '';
switch (true) {
case state.tooLong:
result = `${item.name} 不能超过${item.maxLength}`;
break;
case state.tooShort:
result = `${item.name} 不能少于${item.minLength}`;
break;
case state.patternMismatch:
result = item.dataset.message || item.placeholder || `输入不符合要求`;
break;
}
return result;
}
/**
* password验证pattern
* @param {object} state
*/
pwdTask(state, item) {
let result = '';
if (state.patternMismatch) {
result = item.dataset.message || `输入不符合规则要求`
}
return result;
}
/**
* number和range类型 先验证min和max,再验证step
* @param {object} state
* @param {dom} item
*/
numberTask(state, item) {
let result = '';
switch (true) {
case state.rangeOverflow:
result = `不能超出${item.max}的上限`;
break;
case state.rangeUnderflow:
result = `不能低于${item.min}的下限`;
break;
case state.stepMismatch:
result = item.dataset.message || `${item.value} 不是合法值,需要以${item.step}递增`;
break;
}
return result;
}
/**
* email和url类型 先验证type 再验证pattern
* @param {object} state
* @param {dom} item
*/
emailAndUrl(state, item) {
let result = '';
switch (true) {
case state.typeMismatch: // 适合number、email、url
result = item.dataset.message || item.placeholder || `${item.name} 格式不正确`;
break;
case state.patternMismatch:
result = item.dataset.message || item.placeholder || `输入不符合规则要求`;
break;
}
return result;
}
/**
* 执行验证的方法
*/
validate() {
[...this.fields].reverse().forEach((item) => {
// 验证通过 则跳过本次循环
if (item.checkValidity()) return;
// 返回validityState对象
let state = item.validity,
message = '';
// 首先检测值是否为空
if (state.valueMissing) {
message = item.dataset.has || item.placeholder || `${item.name} 不能为空`;
} else {
// 根据类型执行不同验证
switch (item.type) {
case "text":
case "search":
message = this.textTask(state, item);
break;
case "password":
message = this.pwdTask(state, item);
break;
case "number":
case "range":
message = this.numberTask(state, item);
break;
case "email":
case "url":
message = this.emailAndUrl(state, item);
break;
}
}
// 未知的类型验证
if (state.badInput) {
message = `输入了的值无效`;
}
//设置验证提示信息
item.setCustomValidity(message);
if (message) {
// 手动报告验证的结果 触发元素的focus事件 等待用户输入
item.reportValidity();
// 如果用户有输入 则清除提示信息,最好监听change 避免破坏原有的v-model
item.addEventListener("change", function () {
this.blur();
})
this.flag = false;
}
});
return this.flag;
}
/**
* 调用执行的静态方法
* @param {dom} root
*/
static start(root) {
const obj = new Validate(root);
return obj.validate();
}
}
export default Validate.start;