【JavaScript】常用表單驗證規則

表單驗證規則實現參考

參考了jQuery.validators.js的實現,使用“n~m”來標記範圍

規則 - Rules

validators

使用 - Usage

validators.email("[email protected]"); // true
validators.positive()("12345"); // true
validators.integer("1~2")("123"); // 輸入範圍是1~2
validators.value("0~")("-123.456"); // 輸入值不得小於0

實現 - Source Code

1. validators.js

import hint from "./hint";

/**
 * 表單驗證規則集
 * @namespace
 * @property {function} required - 必填
 * @property {function} number - 數字號碼 | number("6~10") - 長度在6~10間的數字號碼
 * @property {function} numeric - 具有數學意義的數字 | numberic("-10~10") - 值在-10~10間的數值
 * @property {function} length - 字符長度 | length("6~18") - 字符長度在6~18之間
 * @property {function} positive - 正數 | positive("12.8~25.6") - 數學值在12.8~25.6之間
 * @property {function} integer - 整數 | integer("-256~256") - 數學值在-256~256之間
 * @property {function} positiveInteger - 正整數 | positiveInteger("128~256") - 數學值在128~256之間
 * @property {function} email - 郵箱
 * @property {function} ipv4 - IPv4地址 | 255.255.255.255
 * @property {function} port - 端口號 | 0~65535
 * @property {function} idcard18 - 18位大陸身份證 | 結尾可以是X、x
 */
const validators = {
  required: v => notVoid(v) || hint._required,
  number: range => (v = "") =>
    v.match(/^\d+$/)
      ? renderRange(v.length, Range(range, "0~"), hint._length)
      : hint._input_must_be_number,
  numeric: range => (v = "") =>
    numberable(v)
      ? renderRange(v, Range(range), hint._input)
      : hint._input_must_be_number,
  length: range => (v = "") =>
    renderRange(v.length, Range(range, "0~"), hint._length),
  positive: range => (v = "") =>
    positivable(v)
      ? renderRange(v, Range(range), hint._input)
      : hint._input_must_be_positive,
  integer: range => (v = "") =>
    integerable(v)
      ? renderRange(v, Range(range), hint._input)
      : hint._input_must_be_integer,
  positiveInteger: range => (v = "") =>
    positiveIntegerable(v)
      ? renderRange(v, Range(range), hint._input)
      : hint._input_must_be_positive_integer,
  email: (v = "") => Boolean(v.match(/@/)) || hint._email_format_error,
  ipv4: (v = "") =>
    Boolean(
      v.match(
        /^([0-1]?\d?\d|2[0-4]\d|25[0-5])\.([0-1]?\d?\d|2[0-4]\d|25[0-5])\.([0-1]?\d?\d|2[0-4]\d|25[0-5])\.([0-1]?\d?\d|2[0-4]\d|25[0-5])$/
      )
    ) || hint._ip_address_format_error,
  port: (v = "") =>
    positiveIntegerable(v)
      ? renderRange(v, Range("0~65535"), hint._input)
      : hint._port_format_error,
  idcard18: (v = "") =>
    Boolean(
      v.match(
        /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
      )
    ) || hint._id_card_format_error
};

/**
 * 字符串非空
 * @param {string} str - 爲避錯,非字符串會被強制轉換成字符串
 * @returns {boolean} true|false
 */
function notVoid(str = "") {
  if (str == null) {
    return false;
  }
  str = ("" + str).trim();
  return str !== "";
}

/**
 * 字符串是否可以轉換成數字型
 * @see notVoid
 * @param {string} str - 爲避錯,非字符串會被強制轉換成字符串;這樣可以保證[""|null|true|false]不會被change成數字
 * @returns {boolean} true|false
 */
function numberable(str = "") {
  str = ("" + str).trim();
  return notVoid(str) && +str === +str;
}

/**
 * 輸入是否可以轉換成整數
 * @see numberable
 * @param {string} str
 * @returns {boolean} true|false
 */
function integerable(str = "") {
  return numberable(str) && Number.isInteger(+str);
}

/**
 * 輸入是否可以轉換成正數
 * @see numberable
 * @param {string} str
 * @returns {boolean} true|false
 */
function positivable(str = "") {
  return numberable(str) && +str > 0;
}

/**
 * 輸入是否可以轉換成正整數
 * @see numberable
 * @param {string} str
 * @returns {boolean} true|false
 */
function positiveIntegerable(str = "") {
  return integerable(str) && +str > 0;
}

/**
 * 範圍
 * @class Range
 * @param {string} str - 期待輸入爲 "n~m" "n~" "~m"
 * @param {string} extremum - 極值範圍,期待輸入爲 "n~m" "n~" "~m",輸入的str範圍超出此範圍會被截斷
 * @returns {object} {min, max}
 */
function Range(str, extremum) {
  let strRange = str == undefined ? [undefined, undefined] : str.split("~"),
    a = strRange[0],
    b = strRange[1],
    extremumRange =
      extremum == undefined ? [undefined, undefined] : extremum.split("~"),
    minimum = extremumRange[0],
    maximum = extremumRange[1];
  if (numberable(a)) {
    minimum = numberable(minimum) ? Math.max(+a, +minimum) : +a;
  }
  if (numberable(b)) {
    maximum = numberable(maximum) ? Math.min(+b, +maximum) : +b;
  }
  return {
    min: numberable(minimum) ? +minimum : undefined,
    max: numberable(maximum) ? +maximum : undefined
  };
}

/**
 * 範圍的文字顯示函數,使用該函數必須保證首參的值爲numberable
 * @param {string} numberableValue - 一個numberable值
 * @param {Range} range - {min, max}對象
 * @param {string} prefix - 前綴
 */
function renderRange(numberableValue, range, prefix) {
  let { min, max } = range,
    result = true;
  if (min != undefined && max == undefined) {
    result = +numberableValue >= min || prefix + hint._not_less_than + min;
  }
  if (min == undefined && max != undefined) {
    result = +numberableValue <= max || prefix + hint._not_greater_than + max;
  }
  if (min != undefined && max != undefined) {
    result =
      (+numberableValue >= min && +numberableValue <= max) ||
      prefix + hint._range_in + min + "~" + max;
  }
  return result;
}

export default validators;

2. hint.js包含用到的提示語的中文

hint

const hint = {
  _required: "必填",
  _length: "長度",
  _input: "輸入值",
  _not_less_than: "不小於",
  _not_greater_than: "不小於",
  _range_in: "範圍是",
  _input_must_be_number: "輸入必須是數字",
  _input_must_be_positive: "輸入必須是正數",
  _input_must_be_integer: "輸入必須是整數",
  _input_must_be_positive_integer: "輸入必須是正整數",
  _email_format_error: "郵箱格式錯誤",
  _ip_address_format_error: "IP地址格式錯誤",
  _port_format_error: "端口號格式錯誤",
  _id_card_format_error: "身份證格式錯誤"
};

export default hint;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章