common.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import { isPromise } from '../../utils/util';
  2. import { computed, provide, reactive, VNode, watch } from 'vue';
  3. import { FormItemRule } from '../formitem/types';
  4. import { ErrorMessage, FormRule } from './types';
  5. export const component = {
  6. props: {
  7. modelValue: {
  8. type: Object,
  9. default: {}
  10. }
  11. },
  12. components: {},
  13. emits: ['validate'],
  14. setup(props: any, { emit, slots }: any) {
  15. const formErrorTip = computed(() => reactive<any>({}));
  16. provide('formErrorTip', formErrorTip);
  17. const clearErrorTips = (value = props.modelValue) => {
  18. Object.keys(formErrorTip.value).forEach((item) => {
  19. formErrorTip.value[item] = '';
  20. });
  21. };
  22. const reset = () => {
  23. clearErrorTips();
  24. };
  25. watch(
  26. () => props.modelValue,
  27. (value: any) => {
  28. clearErrorTips(value);
  29. },
  30. { immediate: true }
  31. );
  32. const findFormItem = (vnodes: VNode[]) => {
  33. let task: FormRule[] = [];
  34. vnodes.forEach((vnode: VNode, index: number) => {
  35. let type = vnode.type;
  36. type = (type as any).name || type;
  37. if (type == 'nut-form-item') {
  38. task.push({
  39. prop: vnode.props?.['prop'],
  40. rules: vnode.props?.['rules'] || []
  41. });
  42. } else if (Array.isArray(vnode.children) && vnode.children?.length) {
  43. task = task.concat(findFormItem(vnode.children as VNode[]));
  44. }
  45. });
  46. return task;
  47. };
  48. const tipMessage = (errorMsg: ErrorMessage) => {
  49. if (errorMsg.message) {
  50. emit('validate', errorMsg);
  51. }
  52. formErrorTip.value[errorMsg.prop] = errorMsg.message;
  53. };
  54. const checkRule = (item: FormRule): Promise<ErrorMessage | boolean> => {
  55. const { rules, prop } = item;
  56. const _Promise = (errorMsg: ErrorMessage): Promise<ErrorMessage> => {
  57. return new Promise((resolve, reject) => {
  58. tipMessage(errorMsg);
  59. resolve(errorMsg);
  60. });
  61. };
  62. const getPropByPath = (obj: any, keyPath: string) => {
  63. return keyPath.split('.').reduce((prev, curr) => prev[curr], obj);
  64. };
  65. if (!prop) {
  66. console.warn('[NutUI] <FormItem> 使用 rules 校验规则时 , 必须设置 prop 参数');
  67. }
  68. let value = getPropByPath(props.modelValue, prop || '');
  69. // clear tips
  70. tipMessage({ prop, message: '' });
  71. let _rules = [...rules];
  72. while (_rules.length) {
  73. const { required, validator, regex, message } = _rules.shift() as FormItemRule;
  74. const errorMsg = { prop, message };
  75. if (required) {
  76. if (!value) {
  77. return _Promise(errorMsg);
  78. }
  79. }
  80. if (regex && !regex.test(String(value))) {
  81. return _Promise(errorMsg);
  82. }
  83. if (validator) {
  84. const result = validator(value);
  85. if (isPromise(result)) {
  86. return new Promise((r, j) => {
  87. result.then((res) => {
  88. if (!res) {
  89. tipMessage(errorMsg);
  90. r(errorMsg);
  91. } else {
  92. r(true);
  93. }
  94. });
  95. });
  96. } else {
  97. if (!result) {
  98. return _Promise(errorMsg);
  99. }
  100. }
  101. }
  102. }
  103. return Promise.resolve(true);
  104. };
  105. /**
  106. * 校验
  107. * @param customProp 指定校验,用于用户自定义场景时触发,例如 blur、change 事件
  108. * @returns
  109. */
  110. const validate = (customProp: string = '') => {
  111. return new Promise((resolve, reject) => {
  112. let task = findFormItem(slots.default());
  113. let errors = task.map((item) => {
  114. if (customProp) {
  115. if (customProp == item.prop) {
  116. return checkRule(item);
  117. } else {
  118. return Promise.resolve(true);
  119. }
  120. } else {
  121. return checkRule(item);
  122. }
  123. });
  124. Promise.all(errors).then((errorRes) => {
  125. errorRes = errorRes.filter((item) => item != true);
  126. const res = { valid: true, errors: [] };
  127. if (errorRes.length) {
  128. res.valid = false;
  129. res.errors = errorRes as any;
  130. }
  131. resolve(res);
  132. });
  133. });
  134. };
  135. const onSubmit = () => {
  136. validate();
  137. return false;
  138. };
  139. return { validate, reset, onSubmit, formErrorTip };
  140. }
  141. };