fieldCheck.js 8.6 KB

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