// 工具方法 const findParentTd = (element) => { let parent = element.parentElement; while (parent && parent.tagName !== 'TD') { parent = parent.parentElement; } return parent; }; const isSameTd = (element1, element2) => { const td1 = findParentTd(element1); const td2 = findParentTd(element2); return td1 && td1 === td2; }; class ValidationManager { constructor() { this.validations = new Map(); this.dependRules = new Map(); // 存储依赖关系 } // 添加验证规则 add(ruleName, fields, options = {}, priority = 1) { if (!Array.isArray(fields)) { fields = [fields]; } const rule = this._parseRule(ruleName); if (!rule) return; fields.forEach(field => { if (!this.validations.has(field)) { this.validations.set(field, []); } this.validations.get(field).push({ rule: rule, options: { msgPrfx: options.msgPrfx || field, ...options }, priority: priority }); }); if (options.relField) { const relElement = document.querySelector(`[name="${options.relField}"]`); if (relElement) { relElement.addEventListener('change', () => { this.validateField(field); }); } } this.initRequiredMarks(); // ssVm.bindForm(".form-container"); } // 验证单个字段 validateField(field) { const element = document.querySelector(`[name="${field}"]`); if (!element) return { valid: true }; const td = findParentTd(element); if (!td) return { valid: true }; // 获取同一个 td 内的所有需要验证的字段 const tdFields = Array.from(td.querySelectorAll('[name]')) .map(el => el.getAttribute('name')) .filter(name => this.validations.has(name)); // 验证所有字段并合并错误信息 let errors = []; let hasEmptyRequired = false; // 是否有空的必填字段 for (const f of tdFields) { const element = document.querySelector(`[name="${f}"]`); const value = element.value; // 检查是否为空 if (!value || value.trim() === '') { hasEmptyRequired = true; } const result = this._doValidate(f); if (!result.valid && errors.indexOf(result.message) === -1) { errors.push(result.message); } } // 检查是否有依赖规则 const dependRule = this.dependRules.get(field); if (dependRule) { const { dependField, rules } = dependRule; const dependElement = document.querySelector(`[name="${dependField}"]`); if (dependElement) { const dependValue = dependElement.value; const validatorName = rules[dependValue]; if (validatorName) { // 更新验证规则 this.validations.set(field, [{ rule: window.ValidatorRules[validatorName], options: { msgPrfx: field, required: true } }]); } } } // 管理必填标记 let requiredMark = td.querySelector('.required'); if ((hasEmptyRequired || errors.length > 0) && !requiredMark) { requiredMark = document.createElement('div'); requiredMark.className = 'required'; td.appendChild(requiredMark); } else if (!hasEmptyRequired && errors.length === 0 && requiredMark) { requiredMark.remove(); } // 动态管理错误提示 let errTip = td.querySelector('.err-tip'); if (!errTip && errors.length > 0) { errTip = document.createElement('div'); errTip.className = 'err-tip'; errTip.style.position = 'absolute'; errTip.style.zIndex = '1'; errTip.innerHTML = `
${errors.join(';')}
${errors.join(';')}
`; td.appendChild(errTip); } else if (errTip && errors.length === 0) { errTip.remove(); } else if (errTip && errors.length > 0) { errTip.querySelector('.tip').textContent = errors.join(';'); errTip.querySelector('.tip-more').textContent = errors.join(';'); } return { valid: errors.length === 0, message: errors.join(';') }; } // 验证所有字段 validateAll() { const errors = []; for (const field of this.validations.keys()) { const result = this.validateField(field); if (!result.valid) { errors.push({ field: field, message: result.message }); } } console.log("errors",errors); console.log("this.validations",this.validations); return { valid: errors.length === 0, errors: errors }; } // 解析规则名称并获取对应的验证规则 _parseRule(ruleName) { const parts = ruleName.split('.'); const actualRuleName = parts[parts.length - 1]; return ValidatorRules[actualRuleName]; } //执行所有表单校验,并显示校验结果 validateAllAndShowMsg(){ const result = this.validateAll(); console.log("validateAll",result); if (!result.valid) { e.preventDefault(); result.errors.forEach(error => { const element = document.querySelector(`[name="${error.field}"]`); if (element) { const validateComponent = element.closest('.input-container')?.querySelector('.err-tip'); if (validateComponent) { validateComponent.querySelector('.tip').textContent = error.message; validateComponent.querySelector('.tip-more').textContent = error.message; } } }); return false; } return true; } // 绑定到表单提交(本方法已暂停使用) bindForm(formClass) { // 创建一个观察器实例 const observer = new MutationObserver((mutations) => { const form = document.querySelector(formClass); if (form && !form._bound) { console.log("Found form, binding submit event"); $(form).on('submit', (e) => { return this.validateAllAndShowMsg(); }); form._bound = true; // 标记已绑定 observer.disconnect(); // 停止观察 } }); // 开始观察 observer.observe(document.body, { childList: true, subtree: true }); } remove(fields) { // 如果传入单个字段,转换为数组 if (!Array.isArray(fields)) { fields = [fields]; } // 遍历字段并移除验证规则 fields.forEach(field => { if (this.validations.has(field)) { this.validations.delete(field); } }); } // 私有验证方法 _doValidate(field) { const rules = this.validations.get(field); if (!rules) return { valid: true }; const element = document.querySelector(`[name="${field}"]`); if (!element) return { valid: true }; const value = element.value; for (const {rule, options} of rules) { // 如果设置了 required 且值为空,进行必填验证 if (options.required && (!value || value.trim() === '')) { return { valid: false, message: `${options.msgPrfx}不能为空` }; } // 执行规则验证,传入完整的 options 以支持关联字段验证 const isValid = rule.validate(value, options); if (!isValid) { let message = rule.message; message = message.replace('{field}', options.msgPrfx); Object.keys(options).forEach(key => { message = message.replace(`{${key}}`, options[key]); }); return { valid: false, message: message }; } } return { valid: true }; } // 初始化必填标记 initRequiredMarks() { // 先收集所有需要处理的 td const processedTds = new Set(); // 遍历所有带验证规则的字段 for (const [field, rules] of this.validations.entries()) { const element = document.querySelector(`[name="${field}"]`); if (!element) continue; const td = findParentTd(element); if (!td || processedTds.has(td)) continue; // 跳过已处理的 td processedTds.add(td); // 标记该 td 已处理 // 获取同一个 td 内的所有需要验证的字段 const tdFields = Array.from(td.querySelectorAll('[name]')) .map(el => el.getAttribute('name')) .filter(name => this.validations.has(name)); // 只要有验证规则就添加必填标记 if (tdFields.length > 0) { let requiredMark = td.querySelector('.required'); if (!requiredMark) { requiredMark = document.createElement('div'); requiredMark.className = 'required'; td.appendChild(requiredMark); } } } } // 验证字段但不显示错误信息 validateFieldSilent(field) { const rules = this.validations.get(field); if (!rules) return { valid: true }; const element = document.querySelector(`[name="${field}"]`); if (!element) return { valid: true }; const value = element.value; for (const {rule, options} of rules) { if (options.required && (!value || value.trim() === '')) { return { valid: false }; } if (!value && !options.required) { return { valid: true }; } const isValid = rule.validate(value, options); if (!isValid) { return { valid: false }; } } return { valid: true }; } } // 创建全局实例 window.ssVm = window.ssVm || new ValidationManager(); // 在 DOM 加载完成后初始化必填标记