| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /**
- * 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;
|