萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網頁製作 >> 互動設計

手把手構建 JS 表單驗證框架:從 DSL 設計到插件化架構

表單驗證是前端高頻剛需,但重複造輪子既低效又易漏洞。本文從零構建一個聲明式(DSL 風格)、可擴展、整合驗證流程的輕量框架,核心代碼不足 100 行,適合學習架構思想與實戰復用。

設計目標

  1. 聲明式配置:用描述性規則替代控制流邏輯
  2. 全流程整合:統一管理驗證序列、錯誤收集、提交攔截
  3. 開放擴展:驗證器插件化,支援同步/異步、自定義規則

核心類設計

Field 類:單字段驗證協調器

function Field(params) {
  this.field_id = params.fid;        // 目標 input id
  this.validators = params.val;      // 驗證器實例陣列
  this.on_suc = params.suc;          // 成功回調
  this.on_error = params.err;        // 失敗回調
  this.checked = false;              // 驗證狀態
}

Field.prototype.validate = function() {
  for (let validator of this.validators) {
    this.set_callback(validator);
    if (!validator.validate(this.data())) break; // 短路機制
  }
};

Field.prototype.data = function() {
  return document.getElementById(this.field_id).value;
};

Field.prototype.set_callback = function(validator) {
  const self = this;
  validator.on_suc = function() {
    self.checked = true;
    self.on_suc(validator.tips);
  };
  validator.on_error = function() {
    self.checked = false;
    self.on_error(validator.tips);
  };
};

四大驗證器插件

// 1. 長度驗證(含必填)
function Len_val(min, max, tip) {
  this.min_v = min; this.max_v = max; this.tips = tip;
}
Len_val.prototype.validate = function(val) {
  if (val.length < this.min_v || val.length > this.max_v) {
    this.on_error(); return false;
  }
  this.on_suc(); return true;
};

// 2. 正則表達式驗證
function Exp_val(regex, tip) {
  this.exps = regex; this.tips = tip;
}
Exp_val.prototype.validate = function(val) {
  if (!val) { this.on_suc(); return true; } // 非必填空值視為通過
  if (this.exps.test(val)) { this.on_suc(); return true; }
  this.on_error(); return false;
};

// 3. 遠程 AJAX 驗證(依賴 jQuery)
function Remote_val(url, tip) {
  this.p_url = url; this.tips = tip;
}
Remote_val.prototype.validate = function(val) {
  const self = this;
  $.post(this.p_url, { f: val }, function(data) {
    if (data.rs) self.on_suc(); else self.on_error();
  });
  return true; // 異步驗證不阻塞流程,由回調控制最終狀態
};

// 4. 自定義函數驗證(擴展點)
function Custom_val(fn, tip) {
  this.fn = fn; this.tips = tip;
}
Custom_val.prototype.validate = function(val) {
  const result = this.fn(val);
  if (result) this.on_suc(); else this.on_error();
  return result;
};

使用範例

// 實例化字段
const usernameField = new Field({
  fid: 'username',
  val: [
    new Len_val(3, 16, '用戶名長度 3-16 位'),
    new Exp_val(/^[a-zA-Z0-9_]+$/, '僅支援字母數字下劃線'),
    new Remote_val('/api/check-username', '用戶名已存在')
  ],
  suc: (tip) => showSuccess('username', tip),
  err: (tip) => showError('username', tip)
});

// 統一驗證入口
function validateForm() {
  const fields = [usernameField, emailField, passwordField];
  let allValid = true;
  fields.forEach(f => {
    f.validate();
    if (!f.checked) allValid = false;
  });
  return allValid;
}

// 表單提交綁定
document.getElementById('myForm').addEventListener('submit', e => {
  if (!validateForm()) e.preventDefault();
});

架構亮點

  • 關注點分離:Field 只管流程,Validator 只管規則,UI 回調外置
  • 異步友好:Remote_val 非阻塞,配合 Promise 可進一步優化
  • 零依賴核心:除 AJAX 驗證用 jQuery,核心無任何框架綁定
  • 易於測試:每個 Validator 可獨立單元測試

進階擴展方向

  • 引入 Promise 統一異步流程控制
  • 支援驗證分組(如「註冊組」「登入組」)
  • 整合 HTML5 原生驗證 API (validity) 作為基線
  • 輸出 npm 包,提供 TypeScript 類型定義

這個微框架展示了「小而美」的庫設計哲學:做一件事,做透徹,留足擴展縫隙。 歡迎 Fork 迭代出適合你團隊的版本!

copyright © 萬盛學電腦網 all rights reserved