import { isObject } from "../../utils/utils" // 递归遍历处理数据 const recurseData = function(data, keys, cb){ const { children } = keys; if (isObject(data)) { fn(data) } else if (Array.isArray(data)){ for (let i = 0, len = data.length; i < len; i++){ fn(data[i]); } } function fn(obj) { cb(obj) if(Array.isArray(obj[children])){ const list = obj[children]; for (let i = 0, len = list.length; i < len; i++){ fn(list[i]); } } } } // 获取父级节点 const getNodeById = function(node, keys, value){ const { id, children } = keys; if (node[id] === value) { return node; } else if (Array.isArray(node[children])) { let list = node[children]; for (let i = 0, len = list.length; i < len; i++){ let row = list[i]; let pNode = getNodeById(row, keys, value); if (pNode) { return pNode; } } } } //移除节点 const removeNode = function(node, context){ const { keys, data, onlyOneNode } = context; const { id, pid, children } = keys; const oldPaNode = getNodeById(data, keys, node[pid]); const list = oldPaNode[children]; let index; for(let i = 0, len = list.length; i < len; i ++){ if(list[i][id] === node[id]) { list.splice(i, 1) index = i; break; } } // 如果仅移动当前节点,把当前节点的子节点添加到当前节点的父节点,并把当前节点子节点移除 const childNodes = node[children]; if (onlyOneNode && index !== undefined && childNodes) { node[children] = []; childNodes.forEach(it => { it[pid] = oldPaNode[id]; }) oldPaNode[children].splice(index, 0, ...childNodes) } } //新增子节点节点 const addChildNode = function(node, context){ const { parenNode, onlyOneNode, cloneNodeDrag } = context; if( parenNode ){ const { keys } = context; const { id, pid, children } = keys; const nodeClone = JSON.parse(JSON.stringify(node)); if(nodeClone.root) { nodeClone.root = undefined; } if (!cloneNodeDrag) { // 如果拖拽节点 removeNode(nodeClone, context) nodeClone[pid] = parenNode[id]; parenNode[children] ? parenNode[children].push(nodeClone) : parenNode[children] = [].concat(nodeClone); } else { // 如果拷贝并拖拽节点 recurseData(nodeClone, keys, function(item){ if(typeof item[id] === "string" && item[id].indexOf("clone-node") != -1){ item[id] = `clone-node-${item[id]}` } }) if (onlyOneNode && Array.isArray(nodeClone[children])){ nodeClone[children] = []; } nodeClone[keys.pid] = parenNode[keys.id]; parenNode[children] ? parenNode[children].push(nodeClone) : parenNode[children] = [nodeClone]; } } } export default { bind(el, { modifiers, value }, vnode){ let { l, t } = modifiers; const { drag, node, beforeDragEnd } = value; el.addEventListener("mousedown", handleDownCb) let offsetLeft = 0, hasRender = false; let cloneTree = null; let screenX = 0, screenY = 0; function initData(e){ // 初始化拖动数据 e.stopPropagation(); screenX = e.screenX; screenY = e.screenY; offsetLeft = 0; const { context } = vnode; context.contextmenu = false; // 隐藏右键菜单 const { keys, onlyOneNode } = context; if (onlyOneNode) { // 如果是仅移动当前节点 const { children } = keys; const cloneNode = {...node}; cloneNode[children] = []; context.cloneData = cloneNode; } else { context.cloneData = JSON.parse(JSON.stringify(node)); } } function handleDownCb(e){ if( drag === false || e.button!=0 || node.focused || node.noDragging || e.target.className.indexOf('tree-org-node-btn') > -1) { return false } initData(e); document.addEventListener("mousemove",handleMoveCb); document.addEventListener("mouseup", handleUpCb); handleEmit("start") } function moveStart(e){ const { context } = vnode; context.nodeMoving = true; context.stopClick = true; node.moving = true; let ndom = el; while(!ndom.classList.contains("tree-org-node")){ offsetLeft += ndom.offsetLeft; ndom = ndom.offsetParent; } // 拖动节点副本 offsetLeft = offsetLeft + 2; cloneTree = document.querySelector("#clone-tree-org"); cloneTree.style.width = `${ndom.clientWidth}px`; cloneTree.style.opacity = 0.8; cloneTree.style.left = e.clientX - offsetLeft + "px"; cloneTree.style.top = e.clientY + 2 + "px"; } function handleMoveCb(e){ e.preventDefault(); if (Math.abs(e.screenX - screenX) < 5 && Math.abs(e.screenY - screenY) < 5){ return false } if(!hasRender) { hasRender = true; moveStart(e) } if((l&&t) && value){ cloneTree.style.left = e.clientX - offsetLeft + "px"; cloneTree.style.top = e.clientY + 2 + "px"; handleEmit("move") return; } if(l&&value){ el.style.left = e.clientX - offsetLeft+"px"; handleEmit("move") return; } if(t&&value){ el.style.top = e.clientY+"px"; handleEmit("move") return; } } function handleUpCb(e){ document.removeEventListener("mousemove",handleMoveCb); document.removeEventListener("mouseup",handleUpCb); if (!hasRender) { return } if (typeof beforeDragEnd === 'function') { const before = beforeDragEnd(node, vnode.context.parenNode) if (before && before.then) { before.then(() => { doDragEnd(e) }, () => {}) } else if (before !== false) { doDragEnd(e) } } else { doDragEnd(e) } reset() } function reset() { hasRender = false; cloneTree = null; delete node.moving; vnode.context.nodeMoving = false; setTimeout(() => { vnode.context.stopClick = false }, 200) } function doDragEnd(e) { const movingNode = document.querySelector(".tree-org-node__moving"); if (movingNode && movingNode.contains(e.target)) { handleEmit("end", true) return false; } delete node.moving; addChildNode(node, vnode.context) handleEmit("end") } function handleEmit(type){ const { $listeners, parenNode } = vnode.context; if(type === "start") { $listeners['on-node-drag-start'] && $listeners['on-node-drag-start'](node); return } if(type === "move") { $listeners['on-node-drag'] && $listeners['on-node-drag'](node); return } if(type === "end") { $listeners['on-node-drag-end'] && $listeners['on-node-drag-end'](node, parenNode); return } } } }