Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 90 additions & 28 deletions packages/canvas/container/src/CanvasContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@
:windowGetClickEventTarget="target"
:resize="canvasState.type === 'absolute'"
:multiStateLength="multiStateLength"
:isMultiDragging="isMultiDragging"
@select-slot="selectSlot"
@setting="settingModel"
></canvas-action>
</div>
<canvas-multi-drag-indicator
:lineState="lineState"
:multiDragState="multiDragState"
:multiStateLength="multiStateLength"
:isMultiDragging="isMultiDragging"
:getMultiDragPositionText="getMultiDragPositionText"
></canvas-multi-drag-indicator>
<canvas-router-jumper :hoverState="hoverState" :inactiveHoverState="inactiveHoverState"></canvas-router-jumper>
<canvas-viewer-switcher :hoverState="hoverState" :inactiveHoverState="inactiveHoverState"></canvas-viewer-switcher>
<canvas-divider :selectState="computedSelectState"></canvas-divider>
Expand Down Expand Up @@ -62,7 +70,9 @@ import CanvasViewerSwitcher from './components/CanvasViewerSwitcher.vue'
import CanvasResize from './components/CanvasResize.vue'
import CanvasDivider from './components/CanvasDivider.vue'
import CanvasResizeBorder from './components/CanvasResizeBorder.vue'
import CanvasMultiDragIndicator from './components/CanvasMultiDragIndicator.vue'
import { useMultiSelect } from './composables/useMultiSelect'
import { useMultiDrag } from './composables/useMultiDrag'
import {
canvasState,
onMouseUp,
Expand Down Expand Up @@ -92,7 +102,8 @@ export default {
CanvasDivider,
CanvasResizeBorder,
CanvasRouterJumper,
CanvasViewerSwitcher
CanvasViewerSwitcher,
CanvasMultiDragIndicator
},
props: {
controller: Object,
Expand All @@ -113,9 +124,11 @@ export default {
const containerPanel = ref(null)
const insertContainer = ref(false)

const { multiSelectedStates } = useMultiSelect()
const { multiSelectedStates, isMouseDown } = useMultiSelect()

const multiStateLength = computed(() => multiSelectedStates.value.length)
const { startMultiDrag, moveMultiDrag, endMultiDrag, isMultiDragging, getMultiDragPositionText, multiDragState } =
useMultiDrag()

const computedSelectState = computed(() => {
if (multiSelectedStates.value.length === 1) {
Expand All @@ -129,11 +142,26 @@ export default {
const { clientX, clientY } = event
const element = getElement(event.target)
closeMenu()

if (!element) return

// 优先处理右键菜单
if (event.button === 2) {
openMenu(event)
return
}

let node = getCurrent().schema

if (element) {
const currentElement = querySelectById(getCurrent().schema?.id)
// 首先尝试处理多选拖拽开始
// 只有在满足多选条件的情况下才会返回true并阻止后续的选择操作
if (startMultiDrag(event, element)) {
return
}

// 只有当不是多选拖拽的情况下,才进行选择操作
const currentElement = querySelectById(getCurrent().schema?.id)
if (!currentElement?.contains(element) || event.button === 0) {
const isCtrlKey = event.ctrlKey || event.metaKey
const loopId = element.getAttribute(NODE_LOOP)
Expand All @@ -144,15 +172,12 @@ export default {
}
}

// 处理单节点拖拽开始
if (event.button === 0 && element !== element.ownerDocument.body) {
const { x, y } = element.getBoundingClientRect()

dragStart(node, element, { offsetX: clientX - x, offsetY: clientY - y })
}

// 如果是点击右键则打开右键菜单
if (event.button === 2) {
openMenu(event)
if (multiStateLength.value === 1) {
dragStart(node, element, { offsetX: clientX - x, offsetY: clientY - y })
}
}
}
}
Expand Down Expand Up @@ -206,9 +231,10 @@ export default {
const doc = iframe.value.contentDocument
const win = iframe.value.contentWindow

// eslint-disable-next-line @typescript-eslint/no-unused-vars
let isScrolling = false

// 以下是内部iframe监听的事件
// 监听鼠标按下事件
win.addEventListener('mousedown', (event) => {
handleCanvasEvent(() => {
// html元素使用scroll和mouseup事件处理
Expand All @@ -222,6 +248,8 @@ export default {
return
}

isMouseDown.value = true

insertPosition.value = false
insertContainer.value = false
setCurrentNode(event)
Expand All @@ -235,32 +263,62 @@ export default {
isScrolling = true
})

win.addEventListener('mouseup', (event) => {
if (event.target !== doc.documentElement || isScrolling) {
return
}
// 监听鼠标移动事件
win.addEventListener('mousemove', (ev) => {
handleCanvasEvent(() => {
// 优先处理多选拖拽移动
if (!moveMultiDrag(ev)) {
Comment thread
SonyLeo marked this conversation as resolved.
Outdated
// 如果不是多选拖拽,则处理普通拖拽
dragMove(ev, true)
}
})
})

// 监听拖拽结束事件
win.addEventListener('mouseup', (ev) => {
handleCanvasEvent(() => {
if (ev.button === 0 && isMouseDown.value) {
isMouseDown.value = false

// 判断是否需要切换到单选状态
// 只有当点击多选节点但没有拖动时,才需要切换到单选状态
if (multiDragState.keydown && !multiDragState.dragStarted && multiStateLength.value > 1) {
const element = getElement(ev.target)
if (element) {
const clickedNodeId = element?.getAttribute(NODE_UID)
// 只有点击的是多选节点中的一个时才切换到单选
if (clickedNodeId && multiSelectedStates.value.some((state) => state.id === clickedNodeId)) {
selectNode(clickedNodeId)
}
}
}
}

insertPosition.value = false
insertContainer.value = false
setCurrentNode(event)
target.value = event.target
// 优先处理多选拖拽结束
if (!endMultiDrag()) {
// 如果不是多选拖拽,则处理普通拖拽结束
onMouseUp(ev)
}
})
})

// 监听拖拽过程事件
win.addEventListener('dragover', (ev) => {
ev.dataTransfer.dropEffect = 'move'
ev.preventDefault()
dragMove(ev)
// 优先处理多选拖拽移动
if (!moveMultiDrag(ev)) {
dragMove(ev)
}
})

// 监听放置事件
win.addEventListener('drop', (ev) => {
ev.preventDefault()
onMouseUp(ev)
})

win.addEventListener('mousemove', (ev) => {
handleCanvasEvent(() => {
dragMove(ev, true)
})
// 优先处理多选拖拽结束
if (!endMultiDrag()) {
onMouseUp(ev)
}
})

// 阻止浏览器默认的右键菜单功能
Expand Down Expand Up @@ -327,6 +385,7 @@ export default {
document.addEventListener('canvasReady', canvasReady)

return {
isMouseDown,
iframe,
dragState,
hoverState,
Expand All @@ -347,7 +406,10 @@ export default {
insertPosition,
insertContainer,
loading,
srcAttrName
srcAttrName,
isMultiDragging,
multiDragState,
getMultiDragPositionText
}
}
}
Expand Down
58 changes: 57 additions & 1 deletion packages/canvas/container/src/components/CanvasAction.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
v-show="selectState.height && selectState.width"
class="canvas-rect select"
:class="['canvas-rect select', { 'multi-select': multiStateLength > 1 }, { dragging: isMultiDragging }]"
:style="{
top: selectState.top + 'px',
left: selectState.left + 'px',
Expand Down Expand Up @@ -189,6 +189,10 @@ export default {
type: Boolean,
default: false
},
isMultiDragging: {
type: Boolean,
default: false
},
windowGetClickEventTarget: Object
},
emits: ['remove', 'selectSlot', 'setting'],
Expand Down Expand Up @@ -716,7 +720,59 @@ export default {
}
}
}

&.multi-select {
border-color: var(--te-canvas-container-border-color-checked);
border-style: solid;
border-width: 2px;

.corner-mark-left {
background-color: var(--te-canvas-container-bg-color-checked);
color: var(--te-canvas-container-text-color-white);
}

&.dragging {
opacity: 0.7;
border-color: var(--te-canvas-container-border-color-multi, #1890ff);
border-style: dashed;
border-width: 2px;
background-color: rgba(24, 144, 255, 0.15);
box-shadow: 0 0 12px rgba(24, 144, 255, 0.4);
transition: all 0.2s ease;
animation: pulse-border 1.5s infinite;

.corner-mark-left {
background-color: var(--te-canvas-container-border-color-multi, #1890ff);
animation: pulse-bg 1.5s infinite;
}
}
}
}

@keyframes pulse-border {
0% {
box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.4);
}
70% {
box-shadow: 0 0 0 6px rgba(24, 144, 255, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(24, 144, 255, 0);
}
}

@keyframes pulse-bg {
0% {
background-color: rgba(24, 144, 255, 1);
}
50% {
background-color: rgba(24, 144, 255, 0.7);
}
100% {
background-color: rgba(24, 144, 255, 1);
}
}

.short-cut-set.short-cut-set.tiny-popper.tiny-popover {
.tiny-popover__title {
color: var(--te-canvas-container-text-color-primary);
Expand Down
Loading