fieldCheck.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. "use strict";
  2. /**
  3. * 表单字段验证库
  4. * author:kindring
  5. * date:2023/10/08
  6. */
  7. /**
  8. * @typedef {string} errMessage 错误信息
  9. */
  10. /**
  11. * @typedef { Array<string | RegExp> } checkFields 验证字段匹配项
  12. */
  13. /**
  14. * @typedef {Object} checkRule 规则对象
  15. * @property {string} [type] 类型
  16. * @property {number} [min] 最小值
  17. * @property {number} [max] 最大值
  18. * @property {number} [length] 长度
  19. * @property {RegExp} [regex] 正则表达式
  20. * @property {errMessage} [message] 错误信息
  21. * @property {boolean} [require] 是否必须
  22. * @property {number} [minLength] 最小长度
  23. * @property {number} [maxLength] 最大长度
  24. * @property {validatorFunction} [validator] 自定义验证函数
  25. */
  26. /**
  27. * @typedef {function} validatorFunction 自定义验证函数
  28. * @param {any} value 需要验证的值
  29. * @returns {string} 返回错误信息或者 null
  30. */
  31. /**
  32. * @typedef {Object} ruleItem 验证规则对象
  33. * @property {Array<string>} checkFields 需要验证的字段
  34. * @property {Array<validatorFunction | checkRule>} rules 验证规则
  35. */
  36. /**
  37. * @typedef {number} checkCode 验证码
  38. * @property {1} code_pass 验证通过
  39. * @property {2} code_notPass 验证不通过
  40. * @property {3} code_notMatch 未匹配到验证规则
  41. */
  42. /**
  43. * @class FieldCheck
  44. * @description 表单字段验证类
  45. * @property {Array<ruleItem>} ruleItems 验证规则
  46. * @property {function} addRuleItem 添加一条验证规则
  47. * @property {function} verify 检查表单是否符合规则
  48. * @example
  49. * let fieldCheck = new FieldCheck();
  50. * fieldCheck.addRuleItem('rule1',['name'],[
  51. * {
  52. * type: 'string',
  53. * minLength: 2,
  54. * maxLength: 10,
  55. * message: '姓名必须为2-10个字符'
  56. * }
  57. * ]);
  58. * fieldCheck.addRuleItem('rule2',['age'],[
  59. * {
  60. * type: 'number',
  61. * min: 18,
  62. * max: 100,
  63. * message: '年龄必须为18-100岁'
  64. * }]);
  65. * let errMsg = fieldCheck.verify({
  66. * name: 'kindring',
  67. * age: 18});
  68. * console.log(errMsg);
  69. * // null
  70. * let errMsg = fieldCheck.verify({
  71. * name: 'kindring',
  72. * age: 17});
  73. * console.log(errMsg);
  74. * // 年龄必须为18-100岁
  75. */
  76. class FieldCheck{
  77. // 通过
  78. #code_pass = 1;
  79. // 未通过
  80. #code_notPass = 2;
  81. // 无法匹配到验证规则
  82. #code_notMatch = 3;
  83. /**
  84. * @type {Array< ruleItem >}
  85. */
  86. #ruleItems = [];
  87. /**
  88. *
  89. * @param {Array< ruleItem >} [ruleItems] 验证规则数组
  90. */
  91. constructor(ruleItems) {
  92. this.#ruleItems = [];
  93. if(ruleItems && Array.isArray(ruleItems)){
  94. // 使用 addRuleItem 添加规则
  95. for (const ruleItem of ruleItems) {
  96. this.addRuleItem(ruleItem.name || "", ruleItem.checkFields, ruleItem.rules);
  97. }
  98. }
  99. }
  100. /**
  101. * 判断值是否定义
  102. * @param v
  103. * @returns {boolean}
  104. * @private
  105. */
  106. _isDef (v) {
  107. return v !== undefined && v !== null
  108. }
  109. _toString = Object.prototype.toString;
  110. /**
  111. * 判断是否为空
  112. * @param v
  113. * @returns {boolean}
  114. */
  115. _isEmpty(v){
  116. return v === undefined || v === '';
  117. }
  118. _isRegExp (v) {
  119. return this._toString.call(v) === '[object RegExp]'
  120. }
  121. /**
  122. * 构建验证规则
  123. * @param {Array<string | RegExp>} checkFields 需要验证的字段
  124. * @param {Array<validatorFunction | checkRule>} ruleArr 验证规则
  125. * @returns {ruleItem} 验证规则对象
  126. */
  127. buildRuleItem( checkFields , ruleArr) {
  128. // 检测checkFields是否为数组
  129. // 检测ruleArr是否为数组
  130. if(!Array.isArray(checkFields) || !Array.isArray(ruleArr)){
  131. throw new Error('checkFields or ruleArr is not Array');
  132. }
  133. // 检测checkFields中的每一项是否为字符串或者正则
  134. for(let field of checkFields){
  135. if(typeof field !== 'string' && !(field instanceof RegExp)){
  136. throw new Error('checkFields item is not string or RegExp');
  137. }
  138. }
  139. // 检测ruleArr中的每一项是否为函数或者对象
  140. for(let rule of ruleArr){
  141. if(typeof rule !== 'function' && typeof rule !== 'object'){
  142. throw new Error('ruleArr item is not function or object');
  143. }
  144. }
  145. /**
  146. * @type {ruleItem}
  147. */
  148. let ruleItem = {
  149. checkFields: checkFields,
  150. rules: ruleArr
  151. }
  152. // this.ruleItems = this.ruleItems.push(ruleItem);
  153. return ruleItem;
  154. }
  155. /**
  156. * 添加一条验证规则
  157. * @param { string } ruleName 验证规则名,用于区分
  158. * @param { Array<string | RegExp> } checkFields 用于匹配字段的字符或者正则数组
  159. * @param { Array<validatorFunction | checkRule> } ruleArr 验证规则
  160. * @returns { FieldCheck } 返回当前对象
  161. */
  162. addRuleItem( ruleName, checkFields , ruleArr) {
  163. let ruleItem = this.buildRuleItem(checkFields,ruleArr);
  164. this.#ruleItems.push(ruleItem);
  165. return this;
  166. }
  167. /**
  168. * 获取验证规则
  169. * @param { string } field 字段名
  170. * @returns { ruleItem } 验证规则
  171. */
  172. getRuleItem(field){
  173. return this.#ruleItems.find(item => {
  174. // 判断是否为正则
  175. for (const _matchKey of item.checkFields) {
  176. // 判断是否为正则
  177. if (_matchKey instanceof RegExp) {
  178. // console.log(`使用正则进行匹配,${_matchKey.test(key)}`);
  179. if (_matchKey.test(field)) {
  180. // console.log(`通过正则匹配规则成功,${_matchKey.test(key)}`);
  181. return true;
  182. }
  183. } else {
  184. // console.log(`比较是否全等,${_matchKey} === ${key} ?${_matchKey === key}`);
  185. if (_matchKey === field) {
  186. // console.log(`通过字符${_matchKey}匹配成功`);
  187. return true;
  188. }
  189. }
  190. }
  191. return false;
  192. });
  193. }
  194. /**
  195. * 检查字段是否符合规则
  196. * @param field 字段名
  197. * @param value 字段值
  198. * @returns {Array<checkCode | errMessage>} 错误码或错误信息
  199. */
  200. checkField(field, value){
  201. let ruleItem = this.getRuleItem(field);
  202. if(!ruleItem || !ruleItem.rules){
  203. return [this.#code_notMatch];
  204. }
  205. // 判断值是否为undefined
  206. if(value === undefined){
  207. return [this.#code_notPass, '字段值为undefined'];
  208. }
  209. // 开始匹配规则
  210. for(let _rule of ruleItem.rules ){
  211. // 判断是否有自定义验证函数
  212. if(typeof _rule === 'function'){
  213. let _msg = _rule(value);
  214. // console.log(_msg)
  215. if(_msg){
  216. return [this.#code_notPass,_msg]
  217. }
  218. }
  219. // 判断类型
  220. if(_rule.type && typeof value !== _rule.type){
  221. return [this.#code_notPass, _rule.message]
  222. }
  223. // 判断是否为必填项
  224. if(_rule.require && this._isEmpty(value)){
  225. return [this.#code_notPass, _rule.message]
  226. }
  227. // 判断最小值
  228. if(_rule.min && value < _rule.min){
  229. return [this.#code_notPass, _rule.message]
  230. }
  231. // 判断最大值
  232. if(_rule.max && value > _rule.max){
  233. return [this.#code_notPass, _rule.message]
  234. }
  235. // 判断值是否达到指定长度
  236. if(_rule.length && value.length && value.length !== _rule.length){
  237. return [this.#code_notPass, _rule.message]
  238. }
  239. // 判断最小长度
  240. if(_rule.minLength && value.length && value.length < _rule.minLength){
  241. return [this.#code_notPass, _rule.message]
  242. }
  243. // 判断最大长度
  244. if(_rule.maxLength && value.length && value.length > _rule.maxLength){
  245. return [this.#code_notPass, _rule.message]
  246. }
  247. // 判断是否符合正则
  248. if(_rule.regex && !_rule.regex.test(value)){
  249. return [this.#code_notPass, _rule.message]
  250. }
  251. }
  252. return [this.#code_pass]
  253. }
  254. /**
  255. * 检查表单是否符合规则
  256. * @param { Object } formObject 需要检验的表单项 字段:值
  257. * @param [isMustMatch] 是否强制要求匹配规则
  258. * @returns { errMessage } 错误码或错误信息
  259. */
  260. verify(formObject, isMustMatch){
  261. for (const _oKey in formObject) {
  262. let value = formObject[_oKey];
  263. let r = this.checkField(_oKey,value);
  264. if(r[0] === this.#code_notPass){
  265. return r[1]
  266. }else if(isMustMatch && r[0] === this.#code_notMatch){
  267. return `字段没有对应匹配项`
  268. }
  269. }
  270. }
  271. }
  272. export default FieldCheck;