123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import { router } from "@/router";
- import { createVNode, reactive, render, watch, watchEffect } from "vue";
- import Locale from "@/config/locale.vue";
- import type { App, Ref, VNode } from "vue";
- interface ComponentConstructor<P = any> {
- new (...args: any[]): {
- $props: P;
- };
- }
- type Mutable<Type> = {
- -readonly [Key in keyof Type]: Type[Key];
- };
- export type MountContext<P = any> = {
- props?: P;
- children?: unknown;
- element?: HTMLElement;
- app?: App;
- };
- function mount<P>(
- component: Readonly<P>,
- { props, children, element, app }: MountContext<P> = {}
- ) {
- let el = element;
- let vNode: VNode | undefined = createVNode(
- Locale,
- {},
- {
- default: () => createVNode(component, props as any, children),
- }
- );
- if (app && app._context) vNode.appContext = app._context;
- if (el) {
- render(vNode, el);
- } else if (typeof document !== "undefined") {
- render(vNode, (el = document.createElement("div")));
- }
- const destroy = () => {
- if (el) render(null, el);
- el = undefined;
- vNode = undefined;
- };
- return { vNode, destroy, el };
- }
- let app: App;
- export const setApp = (application: App) => (app = application);
- export const extendProps = <T extends {}, E extends {}>(
- origin: T,
- append: E
- ): T & E => {
- const props = reactive({ ...append }) as T & E;
- watchEffect(() => {
- for (const key in origin) {
- (props as any)[key] = origin[key];
- }
- });
- return props;
- };
- export const mountComponent = <P>(
- comp: ComponentConstructor<P>,
- props: Mutable<P>,
- children?: any
- ) => {
- const element = document.createElement("div");
- const { destroy: destroyRaw } = mount(comp, {
- element,
- props,
- app: app,
- children,
- } as any);
- const destroy = () => {
- destroyRaw();
- if (document.body.contains(element)) {
- document.body.removeChild(element);
- }
- stopWatch();
- };
- const stopWatch = watch(() => router.currentRoute.value.name, destroy);
- return destroy;
- };
- import Dialog from "@/components/dialog/index.vue";
- import { DialogProps, dialogPropsKeys } from "@/components/dialog/type";
- export type QuiskExpose = {
- submit?: () => void;
- quit?: () => void;
- } & Partial<{ [key in keyof DialogProps]?: Ref<DialogProps[key]> }>;
- export const quiskMountFactory =
- <P>(comp: ComponentConstructor<P>, dprops: DialogProps) =>
- <T = boolean>(
- props: Mutable<P>,
- dRef?: (expose: { quit: () => void; submit: () => void }) => void
- ): Promise<T> => {
- let ref: QuiskExpose;
- return new Promise((resolve) => {
- const api = {
- onQuit: async () => {
- const ret = ref.quit && ((await ref.quit()) as any);
- if (ret) {
- resolve(ret);
- } else {
- resolve(false as any);
- }
- destroy();
- },
- onSubmit: async () => {
- const ret = ref.submit && ((await ref.submit()) as any);
- if (ret) {
- resolve(ret);
- } else {
- resolve(true as any);
- }
- destroy();
- },
- };
- const layoutProps = reactive({
- ...dprops,
- ref: undefined,
- show: true,
- ...api,
- });
- const destroy = mountComponent(Dialog, layoutProps, {
- default: () =>
- createVNode(comp, {
- ...props,
- ref: (v: any) => {
- for (const key in v) {
- if (dialogPropsKeys.includes(key as any)) {
- (layoutProps as any)[key] = v[key];
- }
- }
- ref = v;
- },
- }),
- });
- dRef &&
- dRef({
- submit: () => api.onSubmit(),
- quit: () => api.onQuit(),
- });
- });
- };
|