modal-api.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. overflow: false,
  44. footer: true,
  45. footerClass: '',
  46. fullscreen: false,
  47. fullscreenButton: true,
  48. header: true,
  49. headerClass: '',
  50. isOpen: false,
  51. loading: false,
  52. modal: true,
  53. openAutoFocus: false,
  54. showCancelButton: true,
  55. showConfirmButton: true,
  56. title: '',
  57. animationType: 'slide',
  58. };
  59. this.store = new Store<ModalState>({
  60. ...defaultState,
  61. ...storeState,
  62. });
  63. this.store.subscribe((state) => {
  64. // 每次更新状态时,都会调用 onOpenChange 回调函数
  65. const prevIsOpen = this.state?.isOpen;
  66. this.state = state;
  67. if (state?.isOpen !== prevIsOpen) {
  68. this.api.onOpenChange?.(!!state?.isOpen);
  69. }
  70. });
  71. this.state = this.store.state;
  72. this.api = {
  73. onBeforeClose,
  74. onCancel,
  75. onClosed,
  76. onConfirm,
  77. onOpenChange,
  78. onOpened,
  79. };
  80. bindMethods(this);
  81. }
  82. /**
  83. * 关闭弹窗
  84. * @description 关闭弹窗时会调用 onBeforeClose 钩子函数,如果 onBeforeClose 返回 false,则不关闭弹窗
  85. */
  86. async close() {
  87. // 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗
  88. // 如果 onBeforeClose 返回 false,则不关闭弹窗
  89. const allowClose = (await this.api.onBeforeClose?.()) ?? true;
  90. if (allowClose) {
  91. this.store.setState((prev) => ({
  92. ...prev,
  93. isOpen: false,
  94. }));
  95. }
  96. }
  97. getData<T extends object = Record<string, any>>() {
  98. return (this.sharedData?.payload ?? {}) as T;
  99. }
  100. /**
  101. * 锁定弹窗状态(用于提交过程中的等待状态)
  102. * @description 锁定状态将禁用默认的取消按钮,使用spinner覆盖弹窗内容,隐藏关闭按钮,阻止手动关闭弹窗,将默认的提交按钮标记为loading状态
  103. * @param isLocked 是否锁定
  104. */
  105. lock(isLocked = true) {
  106. return this.setState({ submitting: isLocked });
  107. }
  108. /**
  109. * 取消操作
  110. */
  111. onCancel() {
  112. if (this.api.onCancel) {
  113. this.api.onCancel?.();
  114. } else {
  115. this.close();
  116. }
  117. }
  118. /**
  119. * 弹窗关闭动画播放完毕后的回调
  120. */
  121. onClosed() {
  122. if (!this.state.isOpen) {
  123. this.api.onClosed?.();
  124. }
  125. }
  126. /**
  127. * 确认操作
  128. */
  129. onConfirm() {
  130. this.api.onConfirm?.();
  131. }
  132. /**
  133. * 弹窗打开动画播放完毕后的回调
  134. */
  135. onOpened() {
  136. if (this.state.isOpen) {
  137. this.api.onOpened?.();
  138. }
  139. }
  140. open() {
  141. this.store.setState((prev) => ({
  142. ...prev,
  143. isOpen: true,
  144. submitting: false,
  145. }));
  146. }
  147. setData<T>(payload: T) {
  148. this.sharedData.payload = payload;
  149. return this;
  150. }
  151. setState(
  152. stateOrFn:
  153. | ((prev: ModalState) => Partial<ModalState>)
  154. | Partial<ModalState>,
  155. ) {
  156. if (isFunction(stateOrFn)) {
  157. this.store.setState(stateOrFn);
  158. } else {
  159. this.store.setState((prev) => ({ ...prev, ...stateOrFn }));
  160. }
  161. return this;
  162. }
  163. /**
  164. * 解除弹窗的锁定状态
  165. * @description 解除由lock方法设置的锁定状态,是lock(false)的别名
  166. */
  167. unlock() {
  168. return this.lock(false);
  169. }
  170. }