mount.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { router } from "@/router";
  2. import { createVNode, reactive, render, watch, watchEffect } from "vue";
  3. import Locale from "@/config/locale.vue";
  4. import type { App, Ref, VNode } from "vue";
  5. export type MountContext<P = any> = {
  6. props?: P;
  7. children?: unknown;
  8. element?: HTMLElement;
  9. app?: App;
  10. };
  11. function mount<P>(
  12. component: Readonly<P>,
  13. { props, children, element, app }: MountContext<P> = {}
  14. ) {
  15. let el = element;
  16. let vNode: VNode | undefined = createVNode(
  17. Locale,
  18. {},
  19. {
  20. default: () => createVNode(component, props as any, children),
  21. }
  22. );
  23. if (app && app._context) vNode.appContext = app._context;
  24. if (el) {
  25. render(vNode, el);
  26. } else if (typeof document !== "undefined") {
  27. render(vNode, (el = document.createElement("div")));
  28. }
  29. const destroy = () => {
  30. if (el) render(null, el);
  31. el = undefined;
  32. vNode = undefined;
  33. };
  34. return { vNode, destroy, el };
  35. }
  36. let app: App;
  37. export const setApp = (application: App) => (app = application);
  38. export const extendProps = <T extends {}, E extends {}>(
  39. origin: T,
  40. append: E
  41. ): T & E => {
  42. const props = reactive({ ...append }) as T & E;
  43. watchEffect(() => {
  44. for (const key in origin) {
  45. (props as any)[key] = origin[key];
  46. }
  47. });
  48. return props;
  49. };
  50. export const mountComponent = <P>(
  51. comp: ComponentConstructor<P>,
  52. props: Mutable<P>,
  53. children?: any
  54. ) => {
  55. const element = document.createElement("div");
  56. const { destroy: destroyRaw } = mount(comp, {
  57. element,
  58. props,
  59. app: app,
  60. children,
  61. } as any);
  62. const destroy = () => {
  63. destroyRaw();
  64. if (document.body.contains(element)) {
  65. document.body.removeChild(element);
  66. }
  67. stopWatch();
  68. };
  69. const stopWatch = watch(() => router.currentRoute.value.name, destroy);
  70. return destroy;
  71. };
  72. import Dialog from "@/components/dialog/index.vue";
  73. import { DialogProps, dialogPropsKeys } from "@/components/dialog/type";
  74. export type QuiskExpose = {
  75. submit?: () => void;
  76. quit?: () => void;
  77. } & Partial<{ [key in keyof DialogProps]?: Ref<DialogProps[key]> }>;
  78. export const quiskMountFactory =
  79. <P>(comp: ComponentConstructor<P>, dprops: DialogProps) =>
  80. <T = boolean>(
  81. props: Mutable<P>,
  82. dRef?: (expose: { quit: () => void; submit: () => void }) => void
  83. ): Promise<T> => {
  84. let ref: QuiskExpose;
  85. return new Promise((resolve) => {
  86. const api = {
  87. onQuit: async () => {
  88. const ret = ref.quit && ((await ref.quit()) as any);
  89. if (ret) {
  90. resolve(ret);
  91. } else {
  92. resolve(false as any);
  93. }
  94. console.error('?')
  95. destroy();
  96. },
  97. onSubmit: async () => {
  98. const ret = ref.submit && ((await ref.submit()) as any);
  99. if (ret) {
  100. resolve(ret);
  101. } else {
  102. resolve(true as any);
  103. }
  104. console.error('?')
  105. destroy();
  106. },
  107. };
  108. const layoutProps = reactive({
  109. ...dprops,
  110. ref: undefined,
  111. show: true,
  112. ...api,
  113. });
  114. const destroy = mountComponent(Dialog, layoutProps, {
  115. default: () =>
  116. createVNode(comp, {
  117. ...props,
  118. ref: (v: any) => {
  119. for (const key in v) {
  120. if (dialogPropsKeys.includes(key as any)) {
  121. layoutProps[key] = v[key];
  122. }
  123. }
  124. ref = v;
  125. },
  126. }),
  127. });
  128. dRef &&
  129. dRef({
  130. submit: () => api.onSubmit(),
  131. quit: () => api.onQuit(),
  132. });
  133. });
  134. };