展示
资源管理器如图-1
图-1
在资源管理器中用户最常用的部分就是下方的图层部分,也是资源管理器最重要的部分,熟悉pixso软件的同学都了解图层的主要作用是什么
图层下面的元素是和画布中的元素一一对应的,用户在修改名字,删除元素时,图层和画布都会同步修改,同时还一个很重要的功能,编组,如图二
图二
多选只需要按住ctrl或者shift,编组是将多个元素创建为一个元素,目的是为了方便用户管理,比如画布中如果有上千个元素,没有编组功能的话,管理就会及其混乱

除了编组外,我们还可以看到有锁定和解锁功能,这两个功能主要是和画布相关联,当选择锁定后,画布里面被锁定的元素,就不能与用户进行交互,比如拖拽,改变大小。
图层还有一个较为重要的功能就是改变元素的顺序,用户可以透过拖拽的方式改变元素顺序,当然元素顺序也是和画布绑定的
鉴于GIF图过于模糊,我就不再展示效果
代码
图层是一个较为复杂的功能,因为我并没有使用到任何的树组件,完全是靠自己以及GPT的帮忙,自主研发了一个tree结构组件,如果有需要,用户也可以自己复制粘贴,放到自己的项目中使用,该组件可以自定义图标,字体样式等等,话不多说,直接展示代码
tree组件
tree组件父级 VueTree.vue
html
<template>
<div class="tree-container">
<tree-node
v-for="node in treeData"
:key="node.id"
:node="node"
:field-names="fieldNames"
:level="0"
@node-click="handleNodeClick"
@switch-lock="emit('switchLock', $event)"
@node-drop="emit('node-drop', $event)"
@update-text="emit('update-text', $event)"
/>
</div>
</template>
<script lang="ts" setup>
import { defineProps, defineEmits, watch, ref, provide } from 'vue'
import TreeNode from './TreeNode.vue'
const props = defineProps({
data: {
type: Array,
required: true
},
fieldNames: {
type: String,
default: 'label'
},
parentSelect: {
type: Array<string>
}
})
const emit = defineEmits([
'node-click',
'selection-change',
'switchLock',
'node-drop',
'update-text'
])
// 处理数据,确保每个节点都有children字段
const treeData = ref<any[]>([])
watch(
props.data,
() => {
treeData.value = props.data.map((node: any) => ({
...node,
children: node.children || []
}))
},
{
deep: true
}
)
watch(
() => props.parentSelect,
(newVal) => {
selectedNodes.value = new Set(props.parentSelect)
}
)
// 多选状态管理
const selectedNodes = ref<Set<string>>(new Set())
const lastSelectedNode = ref<string | null>(null)
// 提供状态给子组件
provide('selectedNodes', selectedNodes)
// 扁平化树结构(用于shift选择)
const flattenTree = (nodes: any[], result: any[] = []): any[] => {
nodes.forEach((node) => {
result.push(node)
if (node.children && node.children.length) {
flattenTree(node.children, result)
}
})
return result
}
const handleNodeClick = (data: { node: any; event: MouseEvent }): void => {
const nodeId = data.node.id
const allNodes = flattenTree(treeData.value)
// Shift选择逻辑
if (data.event.shiftKey && lastSelectedNode.value) {
const allIds = allNodes.map((n) => n.id)
const lastIndex = allIds.indexOf(lastSelectedNode.value)
const currentIndex = allIds.indexOf(nodeId)
if (lastIndex !== -1 && currentIndex !== -1) {
const start = Math.min(lastIndex, currentIndex)
const end = Math.max(lastIndex, currentIndex)
const newSelection = allIds.slice(start, end + 1)
// 保留Ctrl选择项,只添加区间
if (data.event.ctrlKey) {
selectedNodes.value = new Set(newSelection)
} else {
newSelection.forEach((id) => selectedNodes.value.add(id))
}
}
}
// Ctrl选择逻辑
else if (data.event.ctrlKey) {
if (selectedNodes.value.has(nodeId)) {
selectedNodes.value.delete(nodeId)
} else {
selectedNodes.value.add(nodeId)
}
}
// 普通选择逻辑
else {
selectedNodes.value = new Set([nodeId])
}
// 更新最后选择的节点(Shift操作时不更新)
lastSelectedNode.value = nodeId
emit('node-click', data.node)
emit('selection-change', Array.from(selectedNodes.value))
}
//强制更新数据
const forceUpdate = (newData) => {
treeData.value = newData.map((node: any) => ({
...node,
children: node.children || []
}))
}
//清空选中
const clearSelection = () => {
selectedNodes.value.clear()
}
//暴露出去
defineExpose({ forceUpdate, clearSelection })
</script>
<style scoped lang="scss">
/* 原有样式保持不变 */
</style>
tree组件子级 TreeNode.vue
html
<template>
<div class="tree-node">
<div
class="node-content"
:class="{ 'has-children': hasChildren, 'drag-over': dragOverNode === node.id }"
:draggable="true"
:style="{
backgroundColor: isSelected ? '#e4efff' : 'transparent',
color: themeStyle[theme].textColor2
}"
@dragstart="onDragStart"
@dragover="onDragOver"
@drop="onDrop"
@dragleave="onDragLeave"
@click="toggle($event)"
@contextmenu="toggle($event)"
>
<div class="node-content-left">
<span v-if="hasChildren" class="toggle-icon" @click.stop="expandIcon">
<AppstoreOutlined />
</span>
<span v-else class="toggle-icon">
<CodeSandboxOutlined />
</span>
<div class="node-label">
<DblclickEdit
v-model:text="node[fieldNames]"
@start-edit="dbclickStartEdit"
@edited="emit('update-text', { id: node.id, text: $event })"
/>
</div>
</div>
<div class="node-content-right" :style="{ display: node.lock ? 'block' : 'none' }">
<LockOutlined v-if="node.lock" @click="switchLock" />
<UnlockOutlined v-else @click="switchLock" />
</div>
</div>
<div class="animationDiv" :style="{ height }">
<template v-if="hasChildren && expandItems.includes(node.id)">
<div :id="id" class="children">
<div class="line" :style="{ backgroundColor: themeStyle[theme].borderColor1 }"></div>
<tree-node
v-for="child in node.children"
:key="child.id"
:node="child"
:field-names="fieldNames"
:level="level + 1"
@node-click="$emit('node-click', $event)"
@expanded="$emit('expanded', $event)"
@switch-lock="$emit('switchLock', $event)"
@node-drop="$emit('node-drop', $event)"
@update-text="$emit('update-text', $event)"
/>
</div>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
import {
AppstoreOutlined,
CodeSandboxOutlined,
UnlockOutlined,
LockOutlined
} from '@ant-design/icons-vue'
import { computed, ref, inject, Ref, watch } from 'vue'
import { expandItems, setExpandItems, currentExpandItem } from './hook'
import { generateUUID } from '@renderer/utils/utils'
import { useStyleStore } from '@renderer/store/globalStyle/style'
import { storeToRefs } from 'pinia'
import DblclickEdit from '../dbclickEdit/DblclickEdit.vue'
const props = defineProps({
node: {
type: Object,
required: true
},
fieldNames: {
type: String,
default: 'label'
},
level: {
type: Number,
default: 0
}
})
const node = ref(props.node)
watch(
() => props.node,
(val) => {
node.value = val
}
)
const id = ref<string>(generateUUID())
const emit = defineEmits(['node-click', 'expanded', 'switchLock', 'node-drop', 'update-text'])
// 注入选中状态
const selectedNodes = inject<Ref<Set<string>>>('selectedNodes')!
// 计算当前节点是否被选中
const isSelected = computed(() => selectedNodes.value.has(props.node.id))
const hasChildren = computed(() => {
return props.node.children && props.node.children.length > 0
})
//延时展开
const expandTimer = ref<any>(null)
const toggle = (event: MouseEvent): void => {
if (hasChildren.value && expandTimer.value === null) {
expandTimer.value = setTimeout(() => {
expandIcon()
expandTimer.value = null
}, 50)
}
if (!isSelected.value) {
// 传递事件对象给父组件
emit('node-click', { node: props.node, event: event })
}
}
const dbclickStartEdit = (): void => {
if (expandTimer.value) {
clearTimeout(expandTimer.value)
expandTimer.value = null
}
}
const expandIcon = (): void => {
currentExpandItem.value = props.node.id
// 判断是展开还是收起
if (expandItems.value.includes(props.node.id)) {
// 收起
const divElement = document.getElementById(id.value) as HTMLElement
if (divElement) {
// 获取divElement的高度
const divHeight = divElement.offsetHeight
height.value = divHeight + 'px'
setTimeout(() => {
height.value = '0px'
setTimeout(() => {
height.value = undefined
setExpandItems(props.node.id)
}, 300)
}, 100)
}
} else {
// 展开
height.value = '0px'
setTimeout(() => {
const divElement = document.getElementById(id.value) as HTMLElement
if (divElement) {
// 获取divElement的高度
const divHeight = divElement.offsetHeight
height.value = divHeight + 'px'
setTimeout(() => {
height.value = undefined
}, 300)
}
}, 100)
setExpandItems(props.node.id)
}
emit('expanded', props.node)
}
const height = ref<undefined | string>(undefined)
const globalStyleStore = useStyleStore()
const { theme, themeStyle } = storeToRefs(globalStyleStore)
const switchLock = (e: MouseEvent): void => {
//阻止事件冒泡
e.stopPropagation()
emit('switchLock', props.node.id)
}
const dragOverNode = ref<string | null>(null)
const onDragStart = (e: DragEvent) => {
e.dataTransfer?.setData('application/node-id', props.node.id)
e.stopPropagation()
}
const onDragOver = (e: DragEvent) => {
e.preventDefault()
dragOverNode.value = props.node.id
}
const onDrop = (e: DragEvent) => {
e.preventDefault()
const sourceId = e.dataTransfer?.getData('application/node-id')
if (sourceId && sourceId !== props.node.id) {
emit('node-drop', { sourceId, targetId: props.node.id })
}
dragOverNode.value = null
}
const onDragLeave = () => {
dragOverNode.value = null
}
</script>
<style scoped lang="scss">
.tree-node {
margin: 3px 0;
margin-left: 0px;
cursor: pointer;
width: 100%;
text-wrap: nowrap;
.node-content {
padding: 2px;
padding-left: 5px;
transition: background-color 0.2s;
display: flex;
justify-content: space-between;
align-items: center;
&.drag-over {
border-top: 1px solid #409eff;
background-color: #f0faff;
}
&:hover {
.node-content-right {
display: block !important;
}
}
.node-content-left {
display: flex;
justify-content: left;
align-items: center;
.toggle-icon {
display: inline-block;
width: 15px;
text-align: center;
margin-right: 5px;
}
.node-label {
width: 100%;
user-select: none;
cursor: pointer;
line-height: 20px;
}
}
.node-content-right {
padding-right: 10px;
display: none;
}
}
}
.animationDiv {
transition: all 0.3s ease-in-out;
overflow: hidden;
.children {
// max-height: 200px;
width: calc(100% - 15px);
padding-left: 15px;
position: relative;
overflow-y: hidden;
overflow-x: hidden;
.line {
position: absolute;
width: 1px;
height: calc(100% - 10px);
top: 5px;
left: 5.5px;
}
}
}
</style>
tree组件 hook.ts
ts
import { ref } from 'vue'
export const expandItems = ref<string[]>([])
export const currentExpandItem = ref('')
/**
* 设置展开项
* 如果有参数传入,就从expandItems中查找,如果找到了,就删除,如果没有找到,就添加
* 如果没有参数传入,就清空expandItems
*/
export const setExpandItems = (id?: string): void => {
if (id) {
const index = expandItems.value.indexOf(id)
if (index > -1) {
expandItems.value.splice(index, 1)
} else {
expandItems.value.push(id)
}
} else {
expandItems.value = []
}
}
上面是一个完整的tree组件源代码,用户可以完全复制上面的代码,进行运用,该tree组件主要是运用到了递归调用的设计思想,在子级中,如果检测到有children,就会自己调用自己,达到多层级显示的效果,递归调用不仅仅在js,ts代码中能够运用,在html中也可以通过该思想实现一些比较复杂的功能
接下来我将展示我的图层代码
图层代码
layer.vue源代码,里面直接使用到了上述的tree组件
html
<template>
<div class="layer-home">
<Dropdown :trigger="['contextmenu']">
<VueTree
ref="treeRef"
:data="layers"
:field-names="'name'"
:parent-select="currentSelectNodeIds"
@selection-change="layerStore.selectNodes"
@switch-lock="layerStore.toggleLock"
@node-drop="layerStore.moveNode"
@update-text="layerStore.updateNodeText"
></VueTree>
<template #overlay>
<div
class="layer-menu-container"
:style="{
backgroundColor: themeStyle[theme].backgroundColor1,
color: themeStyle[theme].textColor1
}"
>
<template v-for="(item, index) in layerMenu" :key="index">
<div class="layer-menu-item" @click="item.action">
<span>{{ item.name }}</span>
<span>{{ item.shortcutKeys }}</span>
</div>
</template>
</div>
</template>
</Dropdown>
</div>
</template>
<script setup lang="ts">
import VueTree from '@renderer/components/vueTree/VueTree.vue'
import { useLayerStore } from '@renderer/store/resourceBar/layer'
import { storeToRefs } from 'pinia'
import { Dropdown } from 'ant-design-vue'
import { useStyleStore } from '@renderer/store/globalStyle/style'
const layerStore = useLayerStore()
const { layers, treeRef, currentSelectNodeIds } = storeToRefs(layerStore)
const styleStore = useStyleStore()
const { theme, themeStyle } = storeToRefs(styleStore)
const layerMenu = [
{
name: '创建编组',
shortcutKeys: 'Ctrl G',
action: () => {
layerStore.createGroup()
}
},
{
name: '取消编组',
shortcutKeys: 'Ctrl Shift G',
action: () => {
layerStore.ungroup()
}
},
{
name: '锁定',
shortcutKeys: 'Ctrl L'
},
{
name: '解锁',
shortcutKeys: 'Ctrl Shift L'
},
{
name: '删除',
shortcutKeys: 'Delete',
action: () => {
layerStore.deleteNode()
}
}
]
</script>
<style scoped lang="scss">
.layer-home {
width: 100%;
height: 100%;
padding-top: 5px;
overflow: auto;
/* 设置滚动条样式 */
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background-color: #cccccc85;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #aaaaaa85;
}
}
.layer-menu-container {
width: 160px;
box-shadow: 0px 0px 10px #0000001a;
border-radius: 5px;
font-size: 13px;
padding: 10px;
display: flex;
flex-direction: column;
.layer-menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #81818121;
}
}
}
</style>
接下来是图层的store部分代码,store采用的是pinia组件,图层的所有功能的数据处理都在store中进行,包括什么创建编组,取消编组,改名字,删除元素,修改等等
ts
import { ILayerItem } from '@renderer/types/layerType'
import { generateUUID } from '@renderer/utils/utils'
import { defineStore } from 'pinia'
export const useLayerStore = defineStore('layer', {
state: () => ({
layers: [] as ILayerItem[],
//锁定的节点
lockNodeIds: [] as string[],
//当前选择的节点ids
currentSelectNodeIds: [] as string[],
//树形结构ref
treeRef: null as any
}),
actions: {
canvasAddLayer(nodes: any[]) {
console.log(nodes)
nodes.forEach((node: any) => {
this.layers.unshift({
id: node.id,
name: node.name,
zIndex: node.zIndex,
lock: false,
type: 'leaf'
})
})
},
// 获取所有 leaf 类型节点的 id
getLeafNodeIds(ids: string[]): string[] {
const result: string[] = []
for (const id of ids) {
const item = this.findNodeById(this.layers, id)
if (item) {
if (item.type === 'leaf') {
result.push(item.id)
} else if (item.type === 'branch') {
const childIds = item.children?.map((el) => el.id) || []
const leafIds = this.getLeafNodeIds(childIds)
result.push(...leafIds)
}
} else {
result.concat([])
}
}
return result
},
//选择节点,单个或多个
selectNodes(ids: string[]) {
this.currentSelectNodeIds = ids
const leafIds = this.getLeafNodeIds(ids)
window.api.handleCanvasData('selectNodesOrEdges', 'resourceMana', true, [leafIds])
},
//主进程选择节点
selectNodesByMain(result: string[]) {
let ids = [] as string[]
ids = result.filter((id: string) => !this.lockNodeIds.includes(id))
this.currentSelectNodeIds = ids
},
//切换锁的状态
toggleLock(id: string) {
// 找到选中的节点
const item = this.findNodeById(this.layers, id)
if (item) {
item.lock = !item.lock
const currentLockNodeIds = [] as string[]
currentLockNodeIds.push(item.id)
if (item.type === 'branch') {
const getAllIds = (node: ILayerItem) => {
node.lock = item.lock
if (node.type === 'leaf') {
currentLockNodeIds.push(node.id)
} else {
node?.children?.forEach((child: ILayerItem) => {
getAllIds(child)
})
}
}
getAllIds(item)
}
if (item.lock) {
this.lockNodeIds = [...this.lockNodeIds, ...currentLockNodeIds]
} else {
this.lockNodeIds = this.lockNodeIds.filter(
(id: string) => !currentLockNodeIds.includes(id)
)
}
}
},
// 查找所有选中节点信息(含 parent 和 index)
getSelectedNodeInfos(
layers: ILayerItem[],
selectedIds: string[]
): { node: ILayerItem; parent: ILayerItem | null; index: number }[] {
const selected: { node: ILayerItem; parent: ILayerItem | null; index: number }[] = []
const find = (nodes: ILayerItem[], parent: ILayerItem | null): boolean => {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (selectedIds.includes(node.id)) {
selected.push({ node, parent, index: i })
if (selected.length === selectedIds.length) return true
}
if (node.children && find(node.children, node)) {
return true
}
}
return false
}
find(layers, null)
return selected
},
// 获取首个选中节点的信息(用于插入位置)
getFirstSelectedNodeInfo(
nodeInfos: { node: ILayerItem; parent: ILayerItem | null; index: number }[],
firstSelectedId: string
) {
return nodeInfos.find((info) => info.node.id === firstSelectedId)!
},
// 创建新编组对象
createNewGroup(zIndex: number): ILayerItem {
return {
id: generateUUID(),
name: '自定义编组',
lock: false,
type: 'branch',
zIndex,
children: []
}
},
// 将节点移入编组中(注意逆序)
moveNodesToGroup(
nodes: { node: ILayerItem; parent: ILayerItem | null; index: number }[],
group: ILayerItem
) {
;[...nodes]
.sort((a, b) => b.index - a.index)
.forEach((info) => {
const sourceList = info.parent ? info.parent.children! : this.layers
sourceList.splice(info.index, 1)
group.children!.unshift(info.node)
})
},
// 将新编组插入正确位置
insertGroupAtTargetPosition(
group: ILayerItem,
targetInfo: { parent: ILayerItem | null; index: number }
) {
if (targetInfo.parent) {
if (!targetInfo.parent.children) targetInfo.parent.children = []
targetInfo.parent.children.splice(targetInfo.index, 0, group)
} else {
this.layers.splice(targetInfo.index, 0, group)
}
},
createGroup() {
if (this.currentSelectNodeIds.length === 0) return
const selectedNodeInfos = this.getSelectedNodeInfos(this.layers, this.currentSelectNodeIds)
if (selectedNodeInfos.length === 0) return
const firstSelectedInfo = this.getFirstSelectedNodeInfo(
selectedNodeInfos,
this.currentSelectNodeIds[0]
)
const newGroup = this.createNewGroup(firstSelectedInfo.node.zIndex)
this.moveNodesToGroup(selectedNodeInfos, newGroup)
this.insertGroupAtTargetPosition(newGroup, firstSelectedInfo)
},
// 查找节点 by id
findNodeById(nodes: ILayerItem[], id: string): ILayerItem | null {
for (const node of nodes) {
if (node.id === id) return node
if (node.children) {
const foundNode = this.findNodeById(node.children, id)
if (foundNode) return foundNode
}
}
return null
},
// 查找父节点
findParentNode(nodes: ILayerItem[], childId: string): ILayerItem | null {
for (const node of nodes) {
if (node.children && node.children.some((child) => child.id === childId)) {
return node
}
if (node.children) {
const parent = this.findParentNode(node.children, childId)
if (parent) return parent
}
}
return null
},
// 取消编组
ungroup() {
if (this.currentSelectNodeIds.length !== 1) return
const selectedNodeId = this.currentSelectNodeIds[0]
// 找到选中的节点
const selectedNode = this.findNodeById(this.layers, selectedNodeId)
if (!selectedNode || selectedNode.type !== 'branch') return // 确保是 branch 类型的节点
// 查找父节点及其索引位置
const parent = this.findParentNode(this.layers, selectedNodeId)
const nodeIndex = parent
? parent.children!.indexOf(selectedNode)
: this.layers.indexOf(selectedNode)
if (parent) {
// 如果有父节点,将子节点提升到父节点的同一层级
parent.children = parent.children!.filter((child) => child.id !== selectedNodeId)
parent.children!.splice(nodeIndex, 0, ...selectedNode.children!) // 在原位置插入子节点
} else {
// 如果没有父节点,说明是根节点,直接操作根层级
//删除index索引元素
this.layers.splice(nodeIndex, 1)
this.layers.splice(nodeIndex, 0, ...selectedNode.children!) // 在原位置插入子节点
}
// 删除该编组节点的子节点
selectedNode.children = [] // 清空子节点
},
//编组拖拽排序
moveNode(data: any) {
const { sourceId, targetId } = data
if (sourceId === targetId) return
const sourceNode = this.findNodeById(this.layers, sourceId)
const sourceParent = this.findParentNode(this.layers, sourceId)
const targetNode = this.findNodeById(this.layers, targetId)
const targetParent = this.findParentNode(this.layers, targetId)
const sourceIndex = sourceParent
? sourceParent.children!.indexOf(sourceNode!)
: this.layers.indexOf(sourceNode!)
if (sourceIndex !== -1) {
if (sourceParent) {
sourceParent.children!.splice(sourceIndex, 1)
} else {
this.layers.splice(sourceIndex, 1)
}
}
const targetIndex = targetParent
? targetParent.children!.indexOf(targetNode!)
: this.layers.indexOf(targetNode!)
if (targetIndex !== -1) {
if (targetParent) {
targetParent.children!.splice(targetIndex, 0, sourceNode!)
} else {
this.layers.splice(targetIndex, 0, sourceNode!)
}
}
this.updateZIndex(sourceId, targetId)
},
//删除节点
deleteNode(data?: any[]) {
const delHandle = (id: string) => {
const parent = this.findParentNode(this.layers, id)
const index =
parent?.children?.findIndex((item) => item.id === id) ??
this.layers.findIndex((item) => item.id === id)
if (index !== -1) {
if (parent) {
parent.children?.splice(index, 1)
} else {
this.layers.splice(index, 1)
}
}
}
this.currentSelectNodeIds.forEach((id) => {
delHandle(id)
})
if (data) {
const ids = data.map((item) => item.id)
ids.forEach((id) => {
delHandle(id)
})
}
},
updateNodeText(data: { id: string; text: string }) {
const nodes = window.api.handleCanvasData('getNodes', 'resourceMana', false, ['id', data.id])
if (!nodes || nodes.length === 0) {
this.mainUpdateNameToLayer({ id: data.id, name: data.text })
return
}
const node = nodes[0]
node.name = data.text
window.api.handleCanvasData('updateNodes', 'property', true, [node])
},
mainUpdateNameToLayer(data: { id: string; name: string }) {
const result = this.findNodeById(this.layers, data.id)
if (result) {
result.name = data.name
}
},
//更改画布里面节点的zIndex
updateZIndex(sourceId: string, targetId: string) {
const sourceLeftNodes = this.getLeafNodeIds([sourceId])
const targetLeftNodes = this.getLeafNodeIds([targetId])
const targetNodes = [] as any[]
targetLeftNodes.forEach((id) => {
const nodes = window.api.handleCanvasData('getNodes', 'resourceMana', false, ['id', id])
if (nodes && nodes.length > 0) {
targetNodes.push(nodes[0])
}
const edges = window.api.handleCanvasData('getEdges', 'resourceMana', false, ['id', id])
if (edges && edges.length > 0) {
targetNodes.push(edges[0])
}
})
//找到targetNodes里面zIndex最大的值
const maxZIndex = Math.max(...targetNodes.map((node) => node.zIndex))
const sourceNodes = [] as any[]
sourceLeftNodes.forEach((id) => {
const nodes = window.api.handleCanvasData('getNodes', 'resourceMana', false, ['id', id])
if (nodes && nodes.length > 0) {
sourceNodes.push(nodes[0])
}
const edges = window.api.handleCanvasData('getEdges', 'resourceMana', false, ['id', id])
if (edges && edges.length > 0) {
sourceNodes.push(edges[0])
}
})
sourceNodes.forEach((node) => {
node.zIndex = maxZIndex
})
window.api.handleCanvasData('updateNodes', 'resourceMana', true, [sourceNodes])
window.api.handleCanvasData('updateEdges', 'resourceMana', true, [sourceNodes])
},
//清空数据
clear() {
this.layers.splice(0, this.layers.length)
}
}
})
图层部分就到此结束啦,至于资源管理器下面的项目文件和工具预设,都是不重要的功能,作用也不大