fieldCheck.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. /**
  87. *
  88. * @param {Array< ruleItem >} [ruleItems] 验证规则数组
  89. */
  90. constructor(ruleItems) {
  91. this.#ruleItems = [];
  92. if(ruleItems && Array.isArray(ruleItems)){
  93. // 使用 addRuleItem 添加规则
  94. for (const ruleItem of ruleItems) {
  95. this.addRuleItem(ruleItem.name || "", ruleItem.checkFields, ruleItem.rules);
  96. }
  97. }
  98. }
  99. /**
  100. * 判断值是否定义
  101. * @param v
  102. * @returns {boolean}
  103. * @private
  104. */
  105. _isDef (v) {
  106. return v !== undefined && v !== null
  107. }
  108. _toString = Object.prototype.toString;
  109. /**
  110. * 判断是否为空
  111. * @param v
  112. * @returns {boolean}
  113. */
  114. _isEmpty(v){
  115. return v === undefined || v === '';
  116. }
  117. _isRegExp (v) {
  118. return this._toString.call(v) === '[object RegExp]'
  119. }
  120. /**
  121. * 构建验证规则
  122. * @param {Array<string | RegExp>} checkFields 需要验证的字段
  123. * @param {Array<validatorFunction | checkRule>} ruleArr 验证规则
  124. * @returns {ruleItem} 验证规则对象
  125. */
  126. buildRuleItem( checkFields , ruleArr) {
  127. // 检测checkFields是否为数组
  128. // 检测ruleArr是否为数组
  129. if(!Array.isArray(checkFields) || !Array.isArray(ruleArr)){
  130. throw new Error('checkFields or ruleArr is not Array');
  131. }
  132. // 检测checkFields中的每一项是否为字符串或者正则
  133. for(let field of checkFields){
  134. if(typeof field !== 'string' && !(field instanceof RegExp)){
  135. throw new Error('checkFields item is not string or RegExp');
  136. }
  137. }
  138. // 检测ruleArr中的每一项是否为函数或者对象
  139. for(let rule of ruleArr){
  140. if(typeof rule !== 'function' && typeof rule !== 'object'){
  141. throw new Error('ruleArr item is not function or object');
  142. }
  143. }
  144. /**
  145. * @type {ruleItem}
  146. */
  147. let ruleItem = {
  148. checkFields: checkFields,
  149. rules: ruleArr
  150. }
  151. // this.ruleItems = this.ruleItems.push(ruleItem);
  152. return ruleItem;
  153. }
  154. /**
  155. * 添加一条验证规则
  156. * @param { string } ruleName 验证规则名,用于区分
  157. * @param { Array<string | RegExp> } checkFields 用于匹配字段的字符或者正则数组
  158. * @param { Array<validatorFunction | checkRule> } ruleArr 验证规则
  159. * @returns { FieldCheck } 返回当前对象
  160. */
  161. addRuleItem( ruleName, checkFields , ruleArr) {
  162. let ruleItem = this.buildRuleItem(checkFields,ruleArr);
  163. this.#ruleItems.push(ruleItem);
  164. return this;
  165. }
  166. /**
  167. * 获取验证规则
  168. * @param { string } field 字段名
  169. * @returns { ruleItem } 验证规则
  170. */
  171. getRuleItem(field){
  172. return this.#ruleItems.find(item => {
  173. // 判断是否为正则
  174. for (const _matchKey of item.checkFields) {
  175. // 判断是否为正则
  176. if (_matchKey instanceof RegExp) {
  177. // console.log(`使用正则进行匹配,${_matchKey.test(key)}`);
  178. if (_matchKey.test(field)) {
  179. // console.log(`通过正则匹配规则成功,${_matchKey.test(key)}`);
  180. return true;
  181. }
  182. } else {
  183. // console.log(`比较是否全等,${_matchKey} === ${key} ?${_matchKey === key}`);
  184. if (_matchKey === field) {
  185. // console.log(`通过字符${_matchKey}匹配成功`);
  186. return true;
  187. }
  188. }
  189. }
  190. return false;
  191. });
  192. }
  193. /**
  194. * 检查字段是否符合规则
  195. * @param field 字段名
  196. * @param value 字段值
  197. * @returns {Array<checkCode | errMessage>} 错误码或错误信息
  198. */
  199. checkField(field, value){
  200. let ruleItem = this.getRuleItem(field);
  201. if(!ruleItem || !ruleItem.rules){
  202. return [this.#code_notMatch];
  203. }
  204. // 判断值是否为undefined
  205. if(value === undefined){
  206. return [this.#code_notPass, '字段值为undefined'];
  207. }
  208. // 开始匹配规则
  209. for(let _rule of ruleItem.rules ){
  210. // 判断是否有自定义验证函数
  211. if(typeof _rule === 'function'){
  212. let _msg = _rule(value);
  213. // console.log(_msg)
  214. if(_msg){
  215. return [this.#code_notPass,_msg]
  216. }
  217. }
  218. // 判断类型
  219. if(_rule.type && typeof value !== _rule.type){
  220. return [this.#code_notPass, _rule.message]
  221. }
  222. // 判断是否为必填项
  223. if(_rule.require && this._isEmpty(value)){
  224. return [this.#code_notPass, _rule.message]
  225. }
  226. // 判断最小值
  227. if(_rule.min && value < _rule.min){
  228. return [this.#code_notPass, _rule.message]
  229. }
  230. // 判断最大值
  231. if(_rule.max && value > _rule.max){
  232. return [this.#code_notPass, _rule.message]
  233. }
  234. // 判断值是否达到指定长度
  235. if(_rule.length && value.length && value.length !== _rule.length){
  236. return [this.#code_notPass, _rule.message]
  237. }
  238. // 判断最小长度
  239. if(_rule.minLength && value.length && value.length < _rule.minLength){
  240. return [this.#code_notPass, _rule.message]
  241. }
  242. // 判断最大长度
  243. if(_rule.maxLength && value.length && value.length > _rule.maxLength){
  244. return [this.#code_notPass, _rule.message]
  245. }
  246. // 判断是否符合正则
  247. if(_rule.regex && !_rule.regex.test(value)){
  248. return [this.#code_notPass, _rule.message]
  249. }
  250. }
  251. return [this.#code_pass]
  252. }
  253. /**
  254. * 检查表单是否符合规则
  255. * @param { Object } formObject 需要检验的表单项 字段:值
  256. * @param [isMustMatch] 是否强制要求匹配规则
  257. * @returns { errMessage } 错误码或错误信息
  258. */
  259. verify(formObject, isMustMatch){
  260. for (const _oKey in formObject) {
  261. let value = formObject[_oKey];
  262. let r = this.checkField(_oKey,value);
  263. if(r[0] === this.#code_notPass){
  264. return r[1]
  265. }else if(isMustMatch && r[0] === this.#code_notMatch){
  266. return `字段没有对应匹配项`
  267. }
  268. }
  269. }
  270. }
  271. export default FieldCheck;