表單驗證規則實現參考
參考了jQuery.validators.js的實現,使用“n~m”來標記範圍
規則 - Rules
使用 - 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
包含用到的提示語的中文
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;