javascript - 如何用父元素拖动子元素
问题描述
我正在创建一个拖放库,可以动态创建节点,并且每个节点/行都可以创建子节点。
我的问题是,当我拖动一个带有子节点的节点时,只拖动父节点,而子节点不显示拖动。
所以,我唯一的选择是让孩子们在拖动时不显示。
我尝试了不同的方法,我已经阅读了如何做到这一点,但我可以做到这一点。
拖动父级时如何显示子级???
这是我的代码:
import React, { useState, useEffect } from "react";
import {
generatePortalBranch,
replaceBranch,
addBranchInTree,
removeBranchInTree,
findBranchInTree,
} from "../../utils/portal";
import { IBranchProps, IBranch } from "../main/interfaces";
import { getAncestor } from "../../utils/hierarhcy";
export function PortalBranch({
id,
collapsed,
parentId,
level,
title,
tag,
draggable,
editable,
updateName,
checkbox,
checked,
children,
branch,
branchs,
maxPortalChildrens,
onUpdateBranchs,
numBranchs,
onUpdateNumBranchs,
renderPortalBranch,
removeBranchWithChildren,
onUpdatePortalCheckBoxChildren,
onShowModal,
}: IBranchProps) {
let timeout: ReturnType<typeof setTimeout> = setTimeout(() => {}, 0);
let lines: Array<Element> | null;
const [isChecked, setIsChecked] = useState<boolean>(checked);
const [dragging, setDragging] = useState<boolean>(false);
useEffect(() => {
setIsChecked(checked);
}, [checked]);
const onChangeName = (event: any) => {
const newTite: string = event.target.value;
const updatedBranch: IBranch = Object.assign({}, branch, {
title: newTite,
});
let updatedBranchs: Array<IBranch>;
if (parentId === undefined) {
const index = branchs.findIndex((b: IBranch) => b.id === id);
updatedBranchs = Object.assign([], branchs, {
[index]: updatedBranch,
});
} else {
updatedBranchs = replaceBranch(branchs, updatedBranch);
}
onUpdateBranchs(updatedBranchs);
if (event.keyCode === 13) {
onChangeStatusUpdateName();
}
};
const constructScaffold = (space: number) => {
// // Construct the scaffold representing the structure of the tree
const fatherAncestor = getAncestor(branchs, level - space, parentId);
const ancestor = getAncestor(branchs, level - space - 1, parentId);
let lineClass = "go-lineBlock";
if (level === space) {
lineClass = "go-lineBlock go-lineBlock--corner";
} else if (
(fatherAncestor &&
ancestor &&
fatherAncestor.children.indexOf(ancestor) !==
fatherAncestor.children.length - 1) ||
(!fatherAncestor &&
branchs.indexOf(ancestor) !== branchs.length - 1)
) {
lineClass = "go-lineBlock go-lineBlock--vertical";
}
return <div key={`branch-${id}-${space}`} className={lineClass}></div>;
};
const onChangeStatusUpdateName = () => {
const updatedBranch: IBranch = Object.assign({}, branch, {
updateName: !updateName,
});
const updatedBranchs: Array<IBranch> = replaceBranch(
branchs,
updatedBranch
);
onUpdateBranchs(updatedBranchs);
};
const onRemoveBranch = () => {
const updatedBranchs: Array<IBranch> = removeBranchInTree(
branchs,
branch.id
);
onUpdateBranchs(updatedBranchs);
};
const onCreateChildren = () => {
if (maxPortalChildrens === level + 1) return;
let newBranch: IBranch = generatePortalBranch(numBranchs, checkbox);
newBranch = Object.assign({}, newBranch, {
level: level + 1,
parentId: id,
position: children.length,
});
const updatedBranchs: any = addBranchInTree(branchs, newBranch);
onUpdateBranchs(updatedBranchs);
onUpdateNumBranchs(numBranchs + 1);
};
const onSetCheckBox = () => {
onUpdatePortalCheckBoxChildren(branch, !isChecked);
};
const onShowTags = () => {
onShowModal(branch);
};
const onHandleDragStart = (event: any) => {
setDragging(true);
const target: any = event.target;
event.dataTransfer.setData("id", target.id);
const branch: IBranch | null = findBranchInTree(parseInt(target.id), branchs);
let items: Array<HTMLElement> = [];
if (branch && branch.children.length > 0) {
branch.children.forEach( (child: IBranch) => {
const item: HTMLElement | null = document.getElementById(String(child.id));
if (item) items.push(item);
});
}
timeout = setTimeout(() => {
if (items.length > 0) {
items.map( (item: HTMLElement) => item.style.display = "none");
}
target.style.display = "none";
}, 0);
lines = [...target.querySelectorAll(".go-lineBlock")];
lines?.forEach((line: Element) =>
line.classList.add("go-lineBlock--hidden")
);
};
const onHandleDragEnd = () => {
setDragging(false);
clearTimeout(timeout);
};
const onHandleOver = (event: any) => {
event.preventDefault();
};
const enableRemove: boolean = removeBranchWithChildren
? true
: children.length > 0
? false
: true;
return (
<React.Fragment>
<div
className={`complete-branch ${collapsed ? "collapsed" : ""} ${
dragging ? "dragging" : ""
}`}
id={String(id)}
draggable={draggable}
onDragStart={onHandleDragStart}
onDragEnd={onHandleDragEnd}
onDragOver={onHandleOver}
>
{[...Array(level + 1)].map((_level, index) =>
constructScaffold(index)
)}
<div className="go-checkbox" id={String(id)}>
{checkbox && children.length > 0 && (
<label
className="go-react-checkbox mx-2"
id={String(id)}
>
<input
id={String(id)}
type="checkbox"
checked={isChecked}
onChange={onSetCheckBox}
/>
<span className="checkmark" id={String(id)} />
</label>
)}
</div>
<div id={String(id)} className="go-react-branch my-1">
{!tag && (
<div id={String(id)} className="branch-move">
<i className="icon-th" id={String(id)} />
</div>
)}
<div id={String(id)} className="branch-info">
<div id={String(id)} className="branch-title">
{updateName ? (
<input
id={String(id)}
type="text"
value={title}
onChange={onChangeName}
onKeyDown={onChangeName}
/>
) : (
<label id={String(id)}>{title}</label>
)}
</div>
<div id={String(id)} className="branch-icons">
{maxPortalChildrens !== level + 1 && (
<i
id={String(id)}
className="icon-plus-squared-alt"
onClick={onCreateChildren}
/>
)}
{!tag && editable && (
<i
id={String(id)}
className="icon-pencil"
onClick={onChangeStatusUpdateName}
/>
)}
{!tag && editable && enableRemove && (
<i
id={String(id)}
className="icon-trash-empty"
onClick={onRemoveBranch}
/>
)}
{!tag && editable && (
<i
id={String(id)}
className="icon-tags"
onClick={onShowTags}
/>
)}
</div>
</div>
</div>
</div>
{children &&
children.length > 0 &&
children.map((child: IBranch, index: number) => {
return renderPortalBranch(index, child);
})}
</React.Fragment>
);
}
CSS:
* {
margin: 0;
padding: 0;
}
.go-react-tree {
width: 100%;
min-width: 350px;
height: 100vh;
color: $color-background-light-1;
background-color: $color-background-dark-2;
overflow: hidden;
&__create-button {
max-width: 150px;
display: flex;
flex-direction: row;
align-items: center;
cursor: default;
}
i {
cursor: pointer;
}
}
.go-react-branches {
width: 100%;
height: 95%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: baseline;
padding: 10px;
overflow-y: auto;
overflow-x: hidden;
}
.go-react-portal-branches {
position: absolute;
width: 100%;
height: 95%;
padding: 10px;
overflow-y: auto;
overflow-x: auto;
}
.placeholder {
position: relative;
width: 300px;
min-height: 60px;
height: auto;
}
.dragging {
position: relative;
width: 300px;
min-height: 60px;
height: auto;
}
解决方案
推荐阅读
- c++ - [class.union]/3 的注释中的“Absent default member initializers, ...”句子的目的是什么?
- azure-active-directory - Azure AD - 如何将 SPA 的自定义注册和登录组件链接到 Azure AD 的底层流程
- javascript - 如何使用 while(!feof) 只选择一行的第二个和第四个值?
- javascript - Discord.js:如何临时激活外部 js 文件中的事件
- javascript - 将脚本输出重定向到 docker 日志
- python - 为什么这个 DFS 代码只能在生成器中调用它?
- python - 我无法从 QCalendarWidget() 正确获取价值
- javascript - socket.io node.js 和 laravel 问题服务器
- c++ - 是否需要多个 OpenSSL Bio 对象来允许并行请求?
- json - 使用 jq 获取一个值,然后使用该值作为键来获取另一个值