| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- // 工具方法
- 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 = `
- <div class="tip">${errors.join(';')}</div>
- <div class="tip-more">${errors.join(';')}</div>
- `;
- 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 加载完成后初始化必填标记
|