mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-07-03 14:58:47 +08:00
fix(editor): 修复 FloatingBox 拖动时鼠标进入 iframe 区域事件丢失
- 拖拽/缩放开始时插入全屏透明遮罩盖住 iframe,结束时移除,避免事件被 iframe 吞掉 - 修正拖拽标题时 z-index 竞态导致遮罩被浮窗盖住的问题 - 将 body 内边距从 scss 抽取为 bodyStyle 透传,复用方按需自定义
This commit is contained in:
parent
c57ef89715
commit
284be0d276
@ -4,6 +4,7 @@
|
||||
v-model:visible="boxVisible"
|
||||
v-model:width="width"
|
||||
v-model:height="codeBlockEditorHeight"
|
||||
:body-style="{ padding: '0 16px' }"
|
||||
:title="content.name ? `${disabled ? '查看' : '编辑'}${content.name}` : '新增代码'"
|
||||
:position="boxPosition"
|
||||
:before-close="beforeClose"
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<Teleport to="body" v-if="visible">
|
||||
<div ref="target" class="m-editor-float-box" :style="{ ...style, zIndex: curZIndex }" @mousedown="nextZIndex">
|
||||
<div
|
||||
ref="target"
|
||||
class="m-editor-float-box"
|
||||
v-bind="$attrs"
|
||||
:style="{ ...style, zIndex: curZIndex }"
|
||||
@mousedown="nextZIndex"
|
||||
>
|
||||
<div ref="title" class="m-editor-float-box-title">
|
||||
<slot name="title">
|
||||
<span>{{ title }}</span>
|
||||
@ -9,7 +15,7 @@
|
||||
<TMagicButton link size="small" @click="closeHandler"><MIcon :icon="Close"></MIcon></TMagicButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px` }">
|
||||
<div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px`, ...bodyStyle }">
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
</div>
|
||||
@ -17,7 +23,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
|
||||
import { computed, type CSSProperties, nextTick, onBeforeUnmount, provide, ref, useTemplateRef, watch } from 'vue';
|
||||
import { Close } from '@element-plus/icons-vue';
|
||||
import VanillaMoveable from 'moveable';
|
||||
|
||||
@ -39,6 +45,7 @@ const props = withDefaults(
|
||||
defineProps<{
|
||||
position?: Position;
|
||||
title?: string;
|
||||
bodyStyle?: CSSProperties;
|
||||
beforeClose?: (_done: (_cancel?: boolean) => void) => void;
|
||||
}>(),
|
||||
{
|
||||
@ -84,6 +91,31 @@ const style = computed(() => {
|
||||
|
||||
let moveable: VanillaMoveable | null = null;
|
||||
|
||||
// 拖拽/缩放时用于覆盖 iframe 的遮罩,防止鼠标进入 iframe 区域后事件被 iframe 吞掉导致拖拽丢失
|
||||
let dragMask: HTMLDivElement | null = null;
|
||||
|
||||
const showDragMask = () => {
|
||||
if (!dragMask) {
|
||||
dragMask = globalThis.document.createElement('div');
|
||||
dragMask.className = 'm-editor-float-box-drag-mask';
|
||||
}
|
||||
globalThis.document.body.appendChild(dragMask);
|
||||
|
||||
// 拖拽标题时,root 上的 @mousedown="nextZIndex" 会在 dragStart 之后把浮窗 z-index 抬高,
|
||||
// 若此时才读取会拿到旧值导致遮罩被浮窗(及其内部 iframe)盖住,故用 nextTick 在 z-index 稳定后再设置到浮窗之上
|
||||
const setMaskZIndex = () => {
|
||||
if (dragMask) {
|
||||
dragMask.style.zIndex = `${curZIndex.value + 1}`;
|
||||
}
|
||||
};
|
||||
setMaskZIndex();
|
||||
nextTick(setMaskZIndex);
|
||||
};
|
||||
|
||||
const hideDragMask = () => {
|
||||
dragMask?.parentNode?.removeChild(dragMask);
|
||||
};
|
||||
|
||||
const initMoveable = () => {
|
||||
moveable = new VanillaMoveable(globalThis.document.body, {
|
||||
className: 'm-editor-floating-box-moveable',
|
||||
@ -101,6 +133,11 @@ const initMoveable = () => {
|
||||
bounds: { left: 0, top: 0, right: 0, bottom: 0, position: 'css' },
|
||||
});
|
||||
|
||||
moveable.on('dragStart', showDragMask);
|
||||
moveable.on('resizeStart', showDragMask);
|
||||
moveable.on('dragEnd', hideDragMask);
|
||||
moveable.on('resizeEnd', hideDragMask);
|
||||
|
||||
moveable.on('drag', (e) => {
|
||||
e.target.style.transform = e.transform;
|
||||
});
|
||||
@ -115,6 +152,7 @@ const initMoveable = () => {
|
||||
};
|
||||
|
||||
const destroyMoveable = () => {
|
||||
hideDragMask();
|
||||
moveable?.destroy();
|
||||
moveable = null;
|
||||
};
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
</div>
|
||||
|
||||
<FloatingBox
|
||||
:body-style="{ padding: '0 16px' }"
|
||||
v-model:visible="addDialogVisible"
|
||||
v-model:width="width"
|
||||
v-model:height="editorHeight"
|
||||
@ -28,6 +29,7 @@
|
||||
</FloatingBox>
|
||||
|
||||
<FloatingBox
|
||||
:body-style="{ padding: '0 16px' }"
|
||||
v-model:visible="addFromJsonDialogVisible"
|
||||
v-model:width="width"
|
||||
v-model:height="editorHeight"
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
</div>
|
||||
|
||||
<FloatingBox
|
||||
:body-style="{ padding: '0 16px' }"
|
||||
v-model:visible="addDialogVisible"
|
||||
v-model:width="width"
|
||||
v-model:height="editorHeight"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<FloatingBox
|
||||
:body-style="{ padding: '0 16px' }"
|
||||
v-model:visible="boxVisible"
|
||||
v-model:width="width"
|
||||
v-model:height="editorHeight"
|
||||
|
||||
@ -25,10 +25,18 @@
|
||||
.m-editor-float-box-body {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.m-editor-floating-box-moveable {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.m-editor-float-box-drag-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user