我正在从头开始为我的 React 项目创建一个文本编辑器组件。它单独工作正常,但是当我在同一页面上添加另一个实例时,某些或有时所有功能键都会停止工作。另外,有时当我单击 insetImage 或 createLink 图标插入链接或图像时,提示出现的次数与该组件实例的数量一样多。我不知道发生了什么事。我尝试从各种来源获取解决方案,我什至尝试过 gpt 但问题仍然存在。我认为当我单击任何功能键时,所有实例的事件处理程序都会被一一调用(根据我的想法)。这是组件的代码:
import React, { useState, useEffect } from "react";
import ulIcon from "../../assets/svgs/list-ul-alt_svgrepo.com.svg";
import olIcon from "../../assets/svgs/list-ol_svgrepo.com.svg";
import attachMent from "../../assets/svgs/attachment-right-svgrepo-com.svg";
import negativeIcon from "../../assets/svgs/negative sign.svg";
import subscriptIcon from "../../assets/svgs/subscript-svgrepo-com.svg";
import superscriptIcon from "../../assets/svgs/superscript-svgrepo-com.svg";
export default function TextEditor() {
const [editorText, setEditorText] = useState("Enter question here...");
function handleChange(e) {
setEditorText(e.target.value);
}
useEffect(() => {
const handleFunctionalKeyClick = (event) => {
console.log("triggered");
const func = event.target.getAttribute("data-func");
if (func) {
if (func == "insertImage") {
const url = prompt("Enter url here", "http://");
if (url !== null) {
document.execCommand(func, false, url);
}
} else {
document.execCommand(func, false);
}
}
};
const functionalKeysContainer = document.querySelectorAll("[data-func]");
const nodeList = Array.from(functionalKeysContainer);
nodeList.forEach((node) => {
node.addEventListener("click", handleFunctionalKeyClick);
});
return () => {
nodeList.forEach((node) => {
node.removeEventListener("click", handleFunctionalKeyClick);
});
};
}, []);
return (
<div className="flex justify-center items-center flex-col w-full h-dvh">
<div className="EditorContainer flex-col flex gap-2 relative w-fit">
<div className="border-2 border-black rounded-xl p-2">
<div
className="w-[45rem] max-w-full h-fit max-h-20 overflow-y-scroll text-3xl outline-none"
id="editor"
contentEditable
onChange={handleChange}
dangerouslySetInnerHTML={{ __html: editorText }}
/>
</div>
<div
id="functionalKeys"
className="functions bg-white flex gap-1 items-center border-2 border-black rounded-md w-fit p-1 right-2 bottom-[0.5rem] m-auto select-none"
>
<div className="bold" title="Bold" data-func="bold">
B
</div>
<div className="pipe">|</div>
<div className="italic" title="Italic" data-func="italic">
I
</div>
<div className="pipe">|</div>
<div className="underline" title="Underline" data-func="underline">
U
</div>
<div className="pipe">|</div>
<div
className="unorderedList otherFunctionalIcons"
title="unordered-list-icon"
>
<img
src={ulIcon}
alt="attachment icon"
className="p-2 w-full cursor-pointer"
title="unordered-list-icon"
data-func="insertUnorderedList"
/>
</div>
<div className="pipe">|</div>
<div
className="attachment otherFunctionalIcons"
title="ordered-list-icon"
>
<img
src={olIcon}
alt="attachment icon"
className="p-2 w-full cursor-pointer"
title="ordered-list-icon"
data-func="insertOrderedList"
/>
</div>
<div className="pipe">|</div>
<div className="attachment otherFunctionalIcons" title="subscript">
<img
src={subscriptIcon}
alt="attachment icon"
className="p-2 w-full cursor-pointer"
title="subscript"
data-func="subscript"
/>
</div>
<div className="pipe">|</div>
<div className="attachment otherFunctionalIcons" title="superscript">
<img
src={superscriptIcon}
alt="superscript icon"
className="p-2 w-full cursor-pointer"
title="superscript"
data-func="superscript"
/>
</div>
<div className="pipe">|</div>
<div className="attachment otherFunctionalIcons" title="Add image">
<img
src={attachMent}
alt="attachment icon"
className="p-2 w-full cursor-pointer"
title="Add image"
data-func="insertImage"
/>
</div>
<div className="pipe">|</div>
<div
className="removeDecoration p-2 active:bg-[var(--black25)] rounded-lg cursor-pointer"
title="Remove all Decorations"
>
<img
src={negativeIcon}
alt=""
className="h-6"
title="Remove all Decorations"
data-func="removeFormat"
/>
</div>
</div>
</div>
</div>
);
}
目前,我不知道下一步该做什么?我询问了 GPT 但没有一个解决方案有效。
您可以使用以下行将事件侦听器绑定到具有
[data-func]
属性的所有 DOM 元素:
const functionalKeysContainer = document.querySelectorAll("[data-func]");
因此,每个
TextEditor
组件都会将事件侦听器附加到先前安装的 TextEditor
组件的所有 DOM 元素。当您单击具有多个处理程序的元素时,所有处理程序都会立即触发。
手动将事件侦听器附加到每个按钮(或在循环中渲染它们)。删除
useEffect
块,提取 handleFunctionalKeyClick
函数,并将其更改为接受 func
字符串,而不是事件对象:
const handleFunctionalKeyClick = func => {
if (func == "insertImage") {
const url = prompt("Enter url here", "http://");
if (url !== null) {
document.execCommand(func, false, url);
}
} else {
document.execCommand(func, false);
}
};
注意:您也可以将其拆分为多个函数来解决特定的应用程序,例如处理“insertImage”。
现在向每个元素添加
onClick
属性,并传递 func
字符串,而不是使用 data-func
属性:
<img
onClick={() => handleFunctionalKeyClick('insertUnorderedList')}
src={ulIcon}
alt="attachment icon"
className="p-2 w-full cursor-pointer"
title="unordered-list-icon"
/>
id
id
钩子为每个组件生成唯一的 useId
。
export default function TextEditor() {
const id = useId();
const [editorText, setEditorText] = useState("Enter question here...");
使用 id
代替静态“functionKeys”id:
<div
id={id}
className="functions bg-white flex gap-1 items-center border-2 border-black rounded-md w-fit p-1 right-2 bottom-[0.5rem] m-auto select-none"
>
在 useEffect
中附加事件处理程序时,使用
id
选择仅存在于该特定组件中的具有“[data-func]”属性的元素:
const functionalKeysContainer = document.querySelectorAll(`#${id} [data-func]`);