modal-api.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import type { ModalApiOptions, ModalState } from './modal';
  2. import { Store } from '@vben-core/shared/store';
  3. import { bindMethods, isFunction } from '@vben-core/shared/utils';
  4. export class ModalApi {
  5. // 共享数据
  6. public sharedData: Record<'payload', any> = {
  7. payload: {},
  8. };
  9. public store: Store<ModalState>;
  10. private api: Pick<
  11. ModalApiOptions,
  12. | 'onBeforeClose'
  13. | 'onCancel'
  14. | 'onClosed'
  15. | 'onConfirm'
  16. | 'onOpenChange'
  17. | 'onOpened'
  18. >;
  19. // private prevState!: ModalState;
  20. private state!: ModalState;
  21. constructor(options: ModalApiOptions = {}) {
  22. const {
  23. connectedComponent: _,
  24. onBeforeClose,
  25. onCancel,
  26. onClosed,
  27. onConfirm,
  28. onOpenChange,
  29. onOpened,
  30. ...storeState
  31. } = options;
  32. const defaultState: ModalState = {
  33. bordered: true,
  34. centered: false,
  35. class: '',
  36. closeOnClickModal: true,
  37. closeOnPressEscape: true,
  38. confirmDisabled: false,
  39. confirmLoading: false,
  40. contentClass: '',
  41. destroyOnClose: true,
  42. draggable: false,
  43. footer: true,
  44. footerClass: '',
  45. fullscreen: false,
  46. fullscreenButton: true,
  47. header: true,
  48. headerClass: '',
  49. isOpen: false,
  50. loading: false,
  51. modal: true,
  52. openAutoFocus: false,
  53. showCancelButton: true,
  54. showConfirmButton: true,
  55. title: '',
  56. animationType: 'slide',
  57. };
  58. this.store = new Store<ModalState>(
  59. {
  60. ...defaultState,
  61. ...storeState,
  62. },
  63. {
  64. onUpdate: () => {
  65. const state = this.store.state;
  66. // 每次更新状态时,都会调用 onOpenChange 回调函数
  67. if (state?.isOpen === this.state?.isOpen) {
  68. this.state = state;
  69. } else {
  70. this.state = state;
  71. this.api.onOpenChange?.(!!state?.isOpen);
  72. }
  73. },
  74. },
  75. );
  76. this.state = this.store.state;
  77. this.api = {
  78. onBeforeClose,
  79. onCancel,
  80. onClosed,
  81. onConfirm,
  82. onOpenChange,
  83. onOpened,
  84. };
  85. bindMethods(this);
  86. }
  87. /**
  88. * 关闭弹窗
  89. * @description 关闭弹窗时会调用 onBeforeClose 钩子函数,如果 onBeforeClose 返回 false,则不关闭弹窗
  90. */
  91. async close() {
  92. // 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗
  93. // 如果 onBeforeClose 返回 false,则不关闭弹窗
  94. const allowClose = (await this.api.onBeforeClose?.()) ?? true;
  95. if (allowClose) {
  96. this.store.setState((prev) => ({
  97. ...prev,
  98. isOpen: false,
  99. }));
  100. }
  101. }
  102. getData<T extends object = Record<string, any>>() {
  103. return (this.sharedData?.payload ?? {}) as T;
  104. }
  105. /**
  106. * 锁定弹窗状态(用于提交过程中的等待状态)
  107. * @description 锁定状态将禁用默认的取消按钮,使用spinner覆盖弹窗内容,隐藏关闭按钮,阻止手动关闭弹窗,将默认的提交按钮标记为loading状态
  108. * @param isLocked 是否锁定
  109. */
  110. lock(isLocked = true) {
  111. return this.setState({ submitting: isLocked });
  112. }
  113. /**
  114. * 取消操作
  115. */
  116. onCancel() {
  117. if (this.api.onCancel) {
  118. this.api.onCancel?.();
  119. } else {
  120. this.close();
  121. }
  122. }
  123. /**
  124. * 弹窗关闭动画播放完毕后的回调
  125. */
  126. onClosed() {
  127. if (!this.state.isOpen) {
  128. this.api.onClosed?.();
  129. }
  130. }
  131. /**
  132. * 确认操作
  133. */
  134. onConfirm() {
  135. this.api.onConfirm?.();
  136. }
  137. /**
  138. * 弹窗打开动画播放完毕后的回调
  139. */
  140. onOpened() {
  141. if (this.state.isOpen) {
  142. this.api.onOpened?.();
  143. }
  144. }
  145. open() {
  146. this.store.setState((prev) => ({
  147. ...prev,
  148. isOpen: true,
  149. submitting: false,
  150. }));
  151. }
  152. setData<T>(payload: T) {
  153. this.sharedData.payload = payload;
  154. return this;
  155. }
  156. setState(
  157. stateOrFn:
  158. | ((prev: ModalState) => Partial<ModalState>)
  159. | Partial<ModalState>,
  160. ) {
  161. if (isFunction(stateOrFn)) {
  162. this.store.setState(stateOrFn);
  163. } else {
  164. this.store.setState((prev) => ({ ...prev, ...stateOrFn }));
  165. }
  166. return this;
  167. }
  168. /**
  169. * 解除弹窗的锁定状态
  170. * @description 解除由lock方法设置的锁定状态,是lock(false)的别名
  171. */
  172. unlock() {
  173. return this.lock(false);
  174. }
  175. }