From e74bdd41e580707e3c03702c54987d6ccc963a1f Mon Sep 17 00:00:00 2001 From: XanderXiao Date: Fri, 29 Apr 2022 16:02:40 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:clone-node-drag=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=B8=BAfalse=E6=97=B6,=E4=BC=9A=E6=8A=A5=E9=94=99.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/tree-org/src/use-tree.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/tree-org/src/use-tree.ts b/src/components/tree-org/src/use-tree.ts index 3d4544a..4ebcb35 100644 --- a/src/components/tree-org/src/use-tree.ts +++ b/src/components/tree-org/src/use-tree.ts @@ -242,10 +242,10 @@ export const useTree = ( }) const cloneData = reactive({ data: {} }) const nodeargs = computed(() => { - const { cloneNodeDrag, onlyOneNode } = props + const { cloneNodeDrag, onlyOneNode,data } = props return { drag: props.nodeDraggable, - dragData: { keys, nodeMoving, parenNode, cloneNodeDrag, onlyOneNode, contextmenu, cloneData }, + dragData: { keys, nodeMoving, parenNode, cloneNodeDrag, onlyOneNode, contextmenu, cloneData,data }, handleStart: props.nodeDragStart, handleMove: props.nodeDraging, handleEnd: props.nodeDragEnd -- Gitee From 6af7d0c5e4336a4630be81cb08e43889657f59cb Mon Sep 17 00:00:00 2001 From: XanderXiao Date: Fri, 29 Apr 2022 17:16:39 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=E5=BD=93=E8=AE=BE=E7=BD=AE=E4=B8=BA?= =?UTF-8?q?=E6=A8=AA=E5=90=91=E5=B1=95=E7=A4=BA=E6=97=B6,=E5=B1=95?= =?UTF-8?q?=E5=BC=80node=E4=BC=9A=E8=B6=85=E5=87=BA=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/tree-org/src/use-tree.ts | 583 ++++++++++++------------ 1 file changed, 293 insertions(+), 290 deletions(-) diff --git a/src/components/tree-org/src/use-tree.ts b/src/components/tree-org/src/use-tree.ts index 4ebcb35..d41e40e 100644 --- a/src/components/tree-org/src/use-tree.ts +++ b/src/components/tree-org/src/use-tree.ts @@ -3,316 +3,319 @@ import type { SetupContext } from 'vue' import type { INode, IRefs } from '@/utils/types' import type { TreeEmits, TreeProps } from './tree' export const useTree = ( - props: TreeProps, - { emit }: SetupContext, - refs: IRefs + props: TreeProps, + {emit}: SetupContext, + refs: IRefs ) => { - const left = ref(0) - const top = ref(0) - const autoDragging = ref(false) - function onDrag (x: number, y: number) { - autoDragging.value = false - left.value = x - top.value = y - emit('on-drag', { x, y }) - } - function onDragStop (x: number, y: number) { - // 防止拖拽出边界 - const zoom = refs.zoomRef.value as HTMLElement - const orgchart = refs.treeRef.value as HTMLElement - const maxX = zoom.clientWidth / 2 - const maxY = zoom.clientHeight / 2 - let minY = zoom.clientHeight - orgchart.clientHeight - let minX = zoom.clientWidth - orgchart.clientWidth - if (minY > 0) { - minY = 0 + const left = ref(0) + const top = ref(0) + const autoDragging = ref(false) + function onDrag(x: number, y: number) { + autoDragging.value = false + left.value = x + top.value = y + emit('on-drag', {x, y}) } - if (minX > 0) { - minX = 0 + function preventOutOfBounds(x: number, y: number) { + const zoom = refs.zoomRef.value as HTMLElement + const orgchart = refs.treeRef.value as HTMLElement + const maxX = zoom.clientWidth / 2 + const maxY = zoom.clientHeight / 2 + let minY = zoom.clientHeight - orgchart.clientHeight + let minX = zoom.clientWidth - orgchart.clientWidth + if (minY > 0) { + minY = 0 + } + if (minX > 0) { + minX = 0 + } + if (x > maxX) { + left.value = maxX + } else if (x < minX) { + left.value = minX + } else { + left.value = x + } + if (y < minY) { + top.value = minY + } else if (y > maxY) { + top.value = maxY + } else { + top.value = y + } } - if (x > maxX) { - left.value = maxX - } else if (x < minX) { - left.value = minX - } else { - left.value = x + function onDragStop(x: number, y: number) { + preventOutOfBounds(x,y) + emit('on-drag-stop', {x, y}) } - if (y < minY) { - top.value = minY - } else if (y > maxY) { - top.value = maxY - } else { - top.value = y + const nodeMoving = ref(false) + const parenNode = reactive({value: {}}) + function nodeMouseenter(e: MouseEvent, data: INode) { + if (nodeMoving.value) { + parenNode.value = data + } + emit('on-node-mouseenter', e, data) + return true } - emit('on-drag-stop', { x, y }) - } - const nodeMoving = ref(false) - const parenNode = reactive({ value: {} }) - function nodeMouseenter (e: MouseEvent, data: INode) { - if (nodeMoving.value) { - parenNode.value = data + function nodeMouseleave(e: MouseEvent, data: INode) { + if (nodeMoving.value) { + parenNode.value = null + } + emit('on-node-mouseleave', e, data) + return true } - emit('on-node-mouseenter', e, data) - return true - } - function nodeMouseleave (e: MouseEvent, data: INode) { - if (nodeMoving.value) { - parenNode.value = null + const contextmenu = ref(false) + const menuX = ref(0) + const menuY = ref(0) + const menuData = reactive({ + data: {} as INode + }) + function nodeContextmenu(e: MouseEvent, data: INode) { + e.stopPropagation() + e.preventDefault() + contextmenu.value = true + menuX.value = e.clientX + menuY.value = e.clientY + menuData.data = data } - emit('on-node-mouseleave', e, data) - return true - } - const contextmenu = ref(false) - const menuX = ref(0) - const menuY = ref(0) - const menuData = reactive({ - data: {} as INode - }) - function nodeContextmenu (e: MouseEvent, data: INode) { - e.stopPropagation() - e.preventDefault() - contextmenu.value = true - menuX.value = e.clientX - menuY.value = e.clientY - menuData.data = data - } - const scale = ref(1) - function zoomWheel (e: WheelEvent) { - if (!props.scalable) return - e.preventDefault() - // 鼠标滚轮缩放 - if (e.deltaY < 0) { - zoomOrgchart(0.1) - } else { - zoomOrgchart(-0.1) + const scale = ref(1) + function zoomWheel(e: WheelEvent) { + if (!props.scalable) return + e.preventDefault() + // 鼠标滚轮缩放 + if (e.deltaY < 0) { + zoomOrgchart(0.1) + } else { + zoomOrgchart(-0.1) + } + emit('on-zoom', scale.value) } - emit('on-zoom', scale.value) - } - function zoomOrgchart (zoom:number) { - if (!props.scalable) return - const value = Number((Number(scale.value) + zoom).toFixed(1)) - if (zoom > 0) { - scale.value = Math.min(3, value) - } else { - scale.value = Math.max(0.3, value) + function zoomOrgchart(zoom: number) { + if (!props.scalable) return + const value = Number((Number(scale.value) + zoom).toFixed(1)) + if (zoom > 0) { + scale.value = Math.min(3, value) + } else { + scale.value = Math.max(0.3, value) + } } - } - function restoreOrgchart () { - scale.value = 1 - left.value = 0 - top.value = 0 - } - function autoDrag (el: HTMLElement, lf: number, tp: number) { - // 计算偏移量,保持根节点相对页面位置不变 - autoDragging.value = true - const x = el.offsetLeft - lf - const y = el.offsetTop - tp - left.value -= x - top.value -= y - } - let timer:any - function handleClick (e: MouseEvent, data: INode) { - // 取消上次延时未执行的方法 - clearTimeout(timer) - // 执行延时 - timer = setTimeout(() => { - // 此处为单击事件要执行的代码 - emit('on-node-click', e, data) - }, props.clickDelay) - } - function handleDblclick (e: MouseEvent, data: INode) { - // 取消上次延时未执行的方法 - clearTimeout(timer) - // 此处为单击事件要执行的代码 - emit('on-node-dblclick', e, data) - } - function handleExpand (e: MouseEvent, data: INode) { - e.stopPropagation() - const el = document.querySelector('.is-root') as HTMLElement - if (el) { - const left = el.offsetLeft - const top = el.offsetTop - if ('expand' in data) { - data.expand = !data.expand - if (!data.expand && data.children) { - collapse(data.children) + function restoreOrgchart() { + scale.value = 1 + left.value = 0 + top.value = 0 + } + function autoDrag(el: HTMLElement, lf: number, tp: number) { + // 计算偏移量,保持根节点相对页面位置不变 + autoDragging.value = true + const x = el.offsetLeft - lf + const y = el.offsetTop - tp + left.value -= x + top.value -= y + preventOutOfBounds(left.value,top.value); + } + let timer: any + function handleClick(e: MouseEvent, data: INode) { + // 取消上次延时未执行的方法 + clearTimeout(timer) + // 执行延时 + timer = setTimeout(() => { + // 此处为单击事件要执行的代码 + emit('on-node-click', e, data) + }, props.clickDelay) + } + function handleDblclick(e: MouseEvent, data: INode) { + // 取消上次延时未执行的方法 + clearTimeout(timer) + // 此处为单击事件要执行的代码 + emit('on-node-dblclick', e, data) + } + function handleExpand(e: MouseEvent, data: INode) { + e.stopPropagation() + const el = document.querySelector('.is-root') as HTMLElement + if (el) { + const left = el.offsetLeft + const top = el.offsetTop + if ('expand' in data) { + data.expand = !data.expand + if (!data.expand && data.children) { + collapse(data.children) + } + } else { + data.expand = true + } + nextTick(() => { + autoDrag(el, left, top) + }) + emit('on-expand', e, data) } - } else { - data.expand = true - } - nextTick(() => { - autoDrag(el, left, top) - }) - emit('on-expand', e, data) } - } - const keys = reactive(Object.assign({ - id: 'id', - pid: 'pid', - label: 'label', - expand: 'expand', - children: 'children' - }, props.props)) + const keys = reactive(Object.assign({ + id: 'id', + pid: 'pid', + label: 'label', + expand: 'expand', + children: 'children' + }, props.props)) - function handleBlur (e: MouseEvent, data: INode) { - const { children, id, label } = keys - const childNodes = menuData.data[children] || [] - for (let i = childNodes.length; i > 0; i--) { - const item = childNodes[i - 1] - if (item[id] === '' && item[label] === '') { - childNodes.splice(i - 1, 1) - break - } + function handleBlur(e: MouseEvent, data: INode) { + const {children, id, label} = keys + const childNodes = menuData.data[children] || [] + for (let i = childNodes.length; i > 0; i--) { + const item = childNodes[i - 1] + if (item[id] === '' && item[label] === '') { + childNodes.splice(i - 1, 1) + break + } + } + emit('on-node-blur', e, data) } - emit('on-node-blur', e, data) - } - const fullscreen = ref(false) - function handleFullscreen () { - fullscreen.value = !fullscreen.value - if (fullscreen.value) { - launchIntoFullscreen() - } else { - exitFullscreen() + const fullscreen = ref(false) + function handleFullscreen() { + fullscreen.value = !fullscreen.value + if (fullscreen.value) { + launchIntoFullscreen() + } else { + exitFullscreen() + } } - } - function launchIntoFullscreen () { - // 全屏 - const element = refs.eleRef.value as HTMLElement - if (element.requestFullscreen) { - element.requestFullscreen() + function launchIntoFullscreen() { + // 全屏 + const element = refs.eleRef.value as HTMLElement + if (element.requestFullscreen) { + element.requestFullscreen() + } } - } - function exitFullscreen () { - // 退出全屏 - if (document.exitFullscreen) { - document.exitFullscreen() + function exitFullscreen() { + // 退出全屏 + if (document.exitFullscreen) { + document.exitFullscreen() + } } - } - function collapse (list: Array) { - list.forEach((child) => { - if (child.expand) { - child.expand = false - } - child.children && collapse(child.children) - }) - } - const expanded = ref(false) - function expandChange () { - expanded.value = !expanded.value - toggleExpand(props.data, expanded.value) - if (!expanded.value) { - nextTick(() => { - onDragStop(left.value, top.value) - }) + function collapse(list: Array) { + list.forEach((child) => { + if (child.expand) { + child.expand = false + } + child.children && collapse(child.children) + }) } - } - function toggleExpand (data: INode, val: boolean) { - if (Array.isArray(data)) { - data.forEach((item) => { - item.expand = val - if (item.children) { - toggleExpand(item.children, val) + const expanded = ref(false) + function expandChange() { + expanded.value = !expanded.value + toggleExpand(props.data, expanded.value) + if (!expanded.value) { + nextTick(() => { + onDragStop(left.value, top.value) + }) } - }) - } else { - data.expand = val - if (data.children) { - toggleExpand(data.children, val) - } - } - } - const zoomStyle = computed(() => { - return { - width: `${100 / scale.value}%`, - height: `${100 / scale.value}%`, - transform: `scale(${scale.value})` } - }) - const zoomPercent = computed(() => { - return `${Math.round(scale.value * 100)}%` - }) - const dragCancel = computed(() => { - return props.draggableOnNode || !props.nodeDraggable ? '' : '.tree-org-node-label' - }) - const expandTitle = computed(() => { - return expanded.value ? '收起全部节点' : '展开全部节点' - }) - const fullTiltle = computed(() => { - return expanded.value ? '收起全部节点' : '展开全部节点' - }) - const cloneData = reactive({ data: {} }) - const nodeargs = computed(() => { - const { cloneNodeDrag, onlyOneNode,data } = props - return { - drag: props.nodeDraggable, - dragData: { keys, nodeMoving, parenNode, cloneNodeDrag, onlyOneNode, contextmenu, cloneData,data }, - handleStart: props.nodeDragStart, - handleMove: props.nodeDraging, - handleEnd: props.nodeDragEnd + function toggleExpand(data: INode, val: boolean) { + if (Array.isArray(data)) { + data.forEach((item) => { + item.expand = val + if (item.children) { + toggleExpand(item.children, val) + } + }) + } else { + data.expand = val + if (data.children) { + toggleExpand(data.children, val) + } + } } - }) - watch(() => props.horizontal, - () => { - nextTick(() => { - onDragStop(left.value, top.value) - }) + const zoomStyle = computed(() => { + return { + width: `${100 / scale.value}%`, + height: `${100 / scale.value}%`, + transform: `scale(${scale.value})` + } }) - const treeData = ref(props.data) - watch(() => props.data, - () => { - treeData.value = props.data + const zoomPercent = computed(() => { + return `${Math.round(scale.value * 100)}%` }) - const tools = reactive({ - visible: true, - data: { - expand: true, - scale: true, - zoom: true, - restore: true, - fullscreen: true - } - }) - onBeforeMount(() => { - if (typeof props.toolBar === 'object') { - Object.assign(tools.data, props.toolBar) - } else if (!props.toolBar) { - tools.visible = false + const dragCancel = computed(() => { + return props.draggableOnNode || !props.nodeDraggable ? '' : '.tree-org-node-label' + }) + const expandTitle = computed(() => { + return expanded.value ? '收起全部节点' : '展开全部节点' + }) + const fullTiltle = computed(() => { + return expanded.value ? '收起全部节点' : '展开全部节点' + }) + const cloneData = reactive({data: {}}) + const nodeargs = computed(() => { + const {cloneNodeDrag, onlyOneNode, data} = props + return { + drag: props.nodeDraggable, + dragData: {keys, nodeMoving, parenNode, cloneNodeDrag, onlyOneNode, contextmenu, cloneData, data}, + handleStart: props.nodeDragStart, + handleMove: props.nodeDraging, + handleEnd: props.nodeDragEnd + } + }) + watch(() => props.horizontal, + () => { + nextTick(() => { + onDragStop(left.value, top.value) + }) + }) + const treeData = ref(props.data) + watch(() => props.data, + () => { + treeData.value = props.data + }) + const tools = reactive({ + visible: true, + data: { + expand: true, + scale: true, + zoom: true, + restore: true, + fullscreen: true + } + }) + onBeforeMount(() => { + if (typeof props.toolBar === 'object') { + Object.assign(tools.data, props.toolBar) + } else if (!props.toolBar) { + tools.visible = false + } + }) + return { + keys, + left, + top, + menuX, + menuY, + nodeMoving, + zoomStyle, + tools, + zoomPercent, + dragCancel, + expandTitle, + fullTiltle, + nodeargs, + expanded, + fullscreen, + treeData, + autoDragging, + contextmenu, + menuData, + cloneData, + zoomWheel, + onDrag, + onDragStop, + expandChange, + handleFullscreen, + zoomOrgchart, + restoreOrgchart, + handleExpand, + nodeMouseenter, + nodeMouseleave, + nodeContextmenu, + handleBlur, + handleClick, + handleDblclick } - }) - return { - keys, - left, - top, - menuX, - menuY, - nodeMoving, - zoomStyle, - tools, - zoomPercent, - dragCancel, - expandTitle, - fullTiltle, - nodeargs, - expanded, - fullscreen, - treeData, - autoDragging, - contextmenu, - menuData, - cloneData, - zoomWheel, - onDrag, - onDragStop, - expandChange, - handleFullscreen, - zoomOrgchart, - restoreOrgchart, - handleExpand, - nodeMouseenter, - nodeMouseleave, - nodeContextmenu, - handleBlur, - handleClick, - handleDblclick - } -} +} \ No newline at end of file -- Gitee