|
@@ -1,11 +1,20 @@
|
|
|
<template>
|
|
|
<Modal
|
|
|
v-model:open="show"
|
|
|
- :title="title"
|
|
|
:width="width"
|
|
|
+ :wrap-style="{ overflow: 'hidden' }"
|
|
|
:destroyOnClose="true"
|
|
|
+ :maskClosable="false"
|
|
|
>
|
|
|
- <Editor v-model:code="code" v-bind="$attrs"/>
|
|
|
+ <template #title>
|
|
|
+ <div ref="modalTitleRef" style="width: 100%; cursor: move">{{ title }}</div>
|
|
|
+ </template>
|
|
|
+ <template #modalRender="{ originVNode }">
|
|
|
+ <div :style="transformStyle">
|
|
|
+ <component :is="originVNode" />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <Editor v-model:code="code" v-bind="$attrs" :language="language"/>
|
|
|
<template #footer>
|
|
|
<slot name="footer">
|
|
|
<Button @click="close">取消</Button>
|
|
@@ -17,8 +26,9 @@
|
|
|
|
|
|
<script lang="ts">
|
|
|
import { Modal, Button } from "ant-design-vue";
|
|
|
-import { ref, defineComponent } from "vue";
|
|
|
-import Editor from "./Editor.vue";
|
|
|
+import { ref, defineComponent, watch, watchEffect, computed, CSSProperties } from "vue";
|
|
|
+import Editor, { Language } from "./Editor.vue";
|
|
|
+import { useDraggable } from '@vueuse/core';
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: "DEditorModal",
|
|
@@ -41,16 +51,64 @@ export default defineComponent({
|
|
|
setup(_, { emit }) {
|
|
|
const show = ref(false);
|
|
|
const code = ref("");
|
|
|
+ const language = ref<Language>();
|
|
|
+ const modalTitleRef = ref<HTMLElement>();
|
|
|
+
|
|
|
+ const { x, y, isDragging } = useDraggable(modalTitleRef);
|
|
|
+ const startX = ref<number>(0);
|
|
|
+ const startY = ref<number>(0);
|
|
|
+ const startedDrag = ref(false);
|
|
|
+ const transformX = ref(0);
|
|
|
+ const transformY = ref(0);
|
|
|
+ const preTransformX = ref(0);
|
|
|
+ const preTransformY = ref(0);
|
|
|
+ const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 });
|
|
|
+ watch([x, y], () => {
|
|
|
+ if (!startedDrag.value) {
|
|
|
+ startX.value = x.value;
|
|
|
+ startY.value = y.value;
|
|
|
+ const bodyRect = document.body.getBoundingClientRect();
|
|
|
+ const titleRect = modalTitleRef.value?.getBoundingClientRect() || { width: 0, height: 0 };
|
|
|
+ dragRect.value.right = bodyRect.width - titleRect.width;
|
|
|
+ dragRect.value.bottom = bodyRect.height - titleRect.height;
|
|
|
+ preTransformX.value = transformX.value;
|
|
|
+ preTransformY.value = transformY.value;
|
|
|
+ }
|
|
|
+ startedDrag.value = true;
|
|
|
+ });
|
|
|
+ watch(isDragging, () => {
|
|
|
+ if (!isDragging) {
|
|
|
+ startedDrag.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
+ watchEffect(() => {
|
|
|
+ if (startedDrag.value) {
|
|
|
+ transformX.value =
|
|
|
+ preTransformX.value +
|
|
|
+ Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) -
|
|
|
+ startX.value;
|
|
|
+ transformY.value =
|
|
|
+ preTransformY.value +
|
|
|
+ Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) -
|
|
|
+ startY.value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const transformStyle = computed<CSSProperties>(() => {
|
|
|
+ return {
|
|
|
+ transform: `translate(${transformX.value}px, ${transformY.value}px)`,
|
|
|
+ };
|
|
|
+ });
|
|
|
const handleOk = () => {
|
|
|
// TODO: 检验code
|
|
|
emit("ok", code.value);
|
|
|
show.value = false;
|
|
|
};
|
|
|
|
|
|
- const open = (codeStr: string) => {
|
|
|
+ const open = (codeStr: string, lang: Language = 'javascript') => {
|
|
|
show.value = true;
|
|
|
code.value = codeStr;
|
|
|
+ language.value = lang;
|
|
|
};
|
|
|
const close = () => {
|
|
|
show.value = false;
|
|
@@ -61,7 +119,10 @@ export default defineComponent({
|
|
|
close,
|
|
|
code,
|
|
|
handleOk,
|
|
|
- show
|
|
|
+ show,
|
|
|
+ language,
|
|
|
+ modalTitleRef,
|
|
|
+ transformStyle
|
|
|
};
|
|
|
},
|
|
|
});
|