drawer-api.ts 3.9 KB

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