我正在使用 dnd-kit/core 并且无法通过编辑按钮使我的 UserComponent 可编辑。我不认为我写的编辑按钮可能与 dnd-kit 兼容(因为它不起作用)?任何提示或解决方案将不胜感激!!
谢谢。
import React, { useState, useEffect } from 'react';
import { closestCenter, DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
const UserComponent = ({
id,
body
}) => {
const [isEditing, setIsEditing] = useState(false);
const toggleEditing = () => {
setIsEditing(!isEditing);
};
const handleBlur = () `your text`=> {
setIsEditing(false);
};
const {
setNodeRef,
attributes,
listeners,
transition,
transform,
isDragging,
} = useSortable({ id: id })
const style = {
transition,
transform: CSS.Transform.toString(transform),
border: '2px solid black',
marginBottom: 5,
marginTop: 5,
display: "block",
opacity: isDragging ? 0.5 : 1,
}
return (
<>
<div
ref={setNodeRef}
{...attributes}
{...listeners}
style={style}
>
<button onClick={toggleEditing}>Edit</button>
<div
contentEditable={isEditing}
onBlur={handleBlur}
suppressContentEditableWarning
>
{body}
</div>
</div>
</>
)
}
function DragApp() {
const [items, setItems] = useState([
{
id: "1",
name: "Manoj"
},
{
id: "2",
name: "John"
},
{
id: "3",
name: "Ronaldo"
},
{
id: "4",
name: "Harry"
},
{
id: "5",
name: "Jamie"
}
])
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => setItems(data));
}, []);
const sensors = [useSensor(PointerSensor)];
const handleDragEnd = ({active, over}) => {
if (active.id !== over.id) {
setItems((items) => {
const oldIndex = items.findIndex(item => item.id === active.id)
const newIndex = items.findIndex(item => item.id === over.id)
return arrayMove(items, oldIndex, newIndex)
})
}
}
return (
<div
style={{
margin: 'auto',
width: 1000,
textAlign: 'center',
}}
>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext
items={items.map(item => item.id)}
strategy={verticalListSortingStrategy}
>
{
items.map(
item => <UserComponent {...item} key={item.id} />
)
}
</SortableContext>
</DndContext>
</div>
);
}
export default DragApp;
我尝试了上面的代码,并希望编辑按钮使每个 div 都可编辑——每个编辑按钮都特定于 div。
实际的结果是文本通过了,我可以拖放div,但是div不可编辑,编辑按钮不可点击。
你应该添加两件事:
const {
setNodeRef,
attributes,
listeners,
transition,
transform,
isDragging,
} = useSortable({ id: id, disabled: isEditing && true });
class MyPointerSensor extends PointerSensor {
static activators = [
{
eventName: "onPointerDown",
handler: ({ nativeEvent: event }) => {
if (
!event.isPrimary ||
event.button !== 0 ||
isInteractiveElement(event.target)
) {
return false;
}
return true;
},
},
];
}
function isInteractiveElement(element) {
const interactiveElements = [
"button",
"input",
"textarea",
"select",
"option",
];
if (interactiveElements.includes(element.tagName.toLowerCase())) {
return true;
}
return false;
}
它将使按钮、输入和文本区域成为不可拖动的元素。
然后更换传感器:
const sensors = [useSensor(MyPointerSensor)];
您可以在这里获得更多信息:How do I prevent draggable on input and btns
我不得不做一些修改并添加 TypeScript 支持。我正在使用
MuiChip
里面的 DndContext
。 PointerSensor 正在拦截我的 onDelete 指针事件。
<div class="MuiButtonBase-root MuiChip-root MuiChip-filled MuiChip-sizeMedium MuiChip-colorDefault MuiChip-deletable MuiChip-deletableColorDefault MuiChip-filledDefault __className_98cea1 mui-style-11eqgit-MuiButtonBase-root-MuiChip-root-SortableDnDChip" tabindex="0" role="button">
<span class="MuiChip-label MuiChip-labelMedium mui-style-6od3lo-MuiChip-
label">
{text}
</span>
<svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiChip-deleteIcon
MuiChip-deleteIconMedium MuiChip-deleteIconColorDefault MuiChip-
deleteIconFilledColorDefault mui-style-1vgma3c-MuiSvgIcon-root"
focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-
testid="CancelIcon">
<path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12
2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12
10.59 15.59 7 17 8.41 13.41 12 17 15.59z">
</path>
</svg>
</div>
import { PointerEvent } from 'react';
import { PointerSensor, PointerSensorOptions } from '@dnd-kit/core';
const parentHasClass = (element: HTMLElement | null, className: string): boolean => {
if (!element || !element.parentElement) {
return false;
}
return element.parentElement.classList.contains(className);
};
const checkParentClass = (event: Event): boolean => {
const target = event.target as HTMLElement;
return parentHasClass(target, 'MuiChip-deleteIcon');
};
class RestrictedPointerSensor extends PointerSensor {
static activators = [
{
eventName: 'onPointerDown' as const,
handler: ({ nativeEvent: event }: PointerEvent, { onActivation }: PointerSensorOptions) => {
if (checkParentClass(event)) {
return false;
}
onActivation?.({ event });
return true;
},
},
];
}
export default RestrictedPointerSensor;
const sensors = useSensors(
useSensor(RestrictedPointerSensor),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
);