diff --git a/packages/canvas/DesignCanvas/src/api/useCanvas.js b/packages/canvas/DesignCanvas/src/api/useCanvas.js index 5ca4b3302..23c12e7aa 100644 --- a/packages/canvas/DesignCanvas/src/api/useCanvas.js +++ b/packages/canvas/DesignCanvas/src/api/useCanvas.js @@ -317,15 +317,13 @@ const operationTypeMap = { // 4. 根据position参数选择插入位置 let index = parentNode.children.indexOf(referenceNode) - if (index === -1 && referTargetNodeId) { - index = parentNode.children.length - } // 5. 插入节点的逻辑 const childrenNode = toRaw(referenceNode) switch (position) { case 'before': - parentNode.children.unshift(newNodeData) + index = index === -1 ? 0 : index + parentNode.children.splice(index, 0, newNodeData) break case 'out': if (childrenNode) { @@ -337,7 +335,8 @@ const operationTypeMap = { parentNode.children.splice(index + 1, 0, newNodeData) break default: - parentNode.children.push(newNodeData) + index = index === -1 ? parentNode.children.length : index + 1 + parentNode.children.splice(index, 0, newNodeData) break } diff --git a/packages/canvas/container/src/container.js b/packages/canvas/container/src/container.js index 738f68864..723e9de3f 100644 --- a/packages/canvas/container/src/container.js +++ b/packages/canvas/container/src/container.js @@ -328,7 +328,6 @@ const getRect = (element) => { } return element.getBoundingClientRect() } - const insertAfter = ({ parent, node, data }) => { if (!data.id) { data.id = utils.guid() diff --git a/packages/canvas/container/src/keyboard.js b/packages/canvas/container/src/keyboard.js index d43651aba..46ede1205 100644 --- a/packages/canvas/container/src/keyboard.js +++ b/packages/canvas/container/src/keyboard.js @@ -10,11 +10,11 @@ * */ -import { getCurrent, insertNode, selectNode, POSITION, removeNodeById, allowInsert, getConfigure } from './container' +import { ref } from 'vue' import { useHistory, useCanvas, getMetaApi, META_APP } from '@opentiny/tiny-engine-meta-register' +import { getCurrent, insertNode, selectNode, POSITION, removeNodeById, allowInsert, getConfigure } from './container' import { copyObject } from '../../common' import { getClipboardSchema, setClipboardSchema } from './utils' -import { ref, toRaw } from 'vue' const KEY_S = 83 const KEY_Y = 89 @@ -102,38 +102,35 @@ const handleClipboardCut = (event, schema) => { } } -const handleClipboardPaste = (node, schema, parent) => { - if (node?.componentName && schema?.componentName && allowInsert(getConfigure(schema.componentName), node)) { - insertNode({ parent, node: schema, data: { ...node } }, POSITION.IN) - } else { - insertNode({ parent, node: schema, data: { ...node } }, POSITION.BOTTOM) - } -} +const handleClipboardPaste = (nodeList, schema, parent) => { + if (!nodeList.length) return -const handleMultiNodesPaste = (node, schema, parent) => { - if (multiSelectedStates.value.length === 1) { - handleClipboardPaste(node, schema, parent) - return - } - - const selectedStates = multiSelectedStates.value.map(({ schema, parent }) => { - return { node: copyObject(schema), schema: toRaw(schema), parent: toRaw(parent) } + nodeList.forEach((node) => { + if (node?.componentName && schema?.componentName && allowInsert(getConfigure(schema.componentName), node)) { + insertNode({ parent, node: schema, data: node }, POSITION.IN) + } else { + insertNode({ parent, node: schema, data: node }, POSITION.BOTTOM) + } }) +} - selectedStates.forEach(({ node, schema, parent }) => { - handleClipboardPaste(node, schema, parent) - }) +const handleCopyEvent = (event) => { + const selectedNodes = multiSelectedStates.value.map(({ schema }) => copyObject(schema)) + + const dataToCopy = JSON.stringify(selectedNodes) + setClipboardSchema(event, dataToCopy) } const handlerClipboardEvent = (event) => { const { schema, parent } = getCurrent() - const node = getClipboardSchema(event) + const nodeList = getClipboardSchema(event) + switch (event.type) { case 'copy': - setClipboardSchema(event, copyObject(schema)) + handleCopyEvent(event) break case 'paste': - handleMultiNodesPaste(node, schema, parent) + handleClipboardPaste(nodeList, schema, parent) break case 'cut': handleClipboardCut(event, schema) diff --git a/packages/canvas/container/src/utils.js b/packages/canvas/container/src/utils.js index c070b9870..239c8f99f 100644 --- a/packages/canvas/container/src/utils.js +++ b/packages/canvas/container/src/utils.js @@ -13,41 +13,53 @@ /** * 复制节点的schema对象到剪切板,以String形式保存 * @param {*} event ClipboardEvent - * @param {*} node 节点的schema对象 + * @param {*} nodeStr 节点列表的字符串 * @return 复制的剪切板的String */ -export const setClipboardSchema = (event, node) => { - let text - - if (typeof node === 'object') { - text = JSON.stringify(node) - } else { - text = String(node) +export const setClipboardSchema = (event, nodeStr) => { + if (typeof nodeStr !== 'string' || !nodeStr.trim()) { + return null } - event.clipboardData.setData('text/plain', text) + // 将 nodeStr 存储到剪贴板 + event.clipboardData.setData('text/plain', nodeStr) event.preventDefault() - return text + return nodeStr } const translateStringToSchema = (clipText) => { - if (!clipText) { - return null + if (typeof clipText !== 'string' || !clipText.trim()) { + return [] } - let data - try { - data = JSON.parse(clipText) - if (!data || !data.componentName) { - data = null + const parsedData = JSON.parse(clipText) + + // 如果是数组且每个项都有 componentName + if (Array.isArray(parsedData) && parsedData.every((item) => item && item.componentName)) { + return parsedData + } else if (!Array.isArray(parsedData) && parsedData.componentName) { + // 如果解析结果不是数组,将其转为数组 + return [parsedData] } } catch (error) { - data = null + // eslint-disable-next-line no-console + console.warn('剪贴板数据解析失败,转换为文本组件:', error) } - return data + // 如果 JSON 解析失败或不符合格式,默认返回一个文本组件 + return [ + { + componentName: 'Text', + props: { + style: 'display: inline-block;', + text: clipText, + className: 'component-base-style' + }, + children: [] + } + ] } /**