用reactjs中的渲染组件替换contentEditable的占位符

cbjzeqam  于 2023-05-22  发布在  React
关注(0)|答案(1)|浏览(167)

我正试图在我的可编辑div中将占位符(如**#fa-face-smile#**)替换为fontawesome表情符号。

<div
        contentEditable="true"
        ref={newMessageRef}
        className={`form-control ${errors.message ? 'is-invalid' : ''}`}
        data-raw=""
        onBlur={e => setNewEditableContent(e.target.textContent)}
    />

所以我在我的可编辑div中编写并插入表情符号如下:
如果#fa-face-smile#能转换成实际的表情符号,我会很高兴的。”
它应该将占位符转换为:

<FontAwesomeIcon size="2x" icon="fa-solid fa-face-smile" />

我用来更新可编辑div的innerHTML的函数是:

function convertEmoticons(string) {
    
        let replacedText = string
            .split(new RegExp(/\#(.*?)\#/, "gi"))
            .map((node, i) => (i % 2 ? <FontAwesomeIcon style={{color: '#a70000'}} size="2x" icon={getEmoticon(node)}/> : node));
    
        return (replacedText);
    }

新消息的设置如下:

const _setMessageText = (text) => {
    newMessageRef.current.setAttribute("data-raw", text);
    newMessageRef.current.textContent = convertEmoticons(text);
}

图标是这样插入的:

const insertEmoticon = (icon) => {

    let currentText = _getMessageText();
    let caretPos = getCaretPosition(newMessageRef.current);
    let iconPlaceholder = "#" + icon + "#";
    let newText = [currentText.slice(0, caretPos), iconPlaceholder, currentText.slice(caretPos)].join(' ');

    _setMessageText(newText);

}

然而,我得到的只是**,[object,object],**。也注意到开头和结尾的逗号了吗?!

如何实现在设置可编辑div的newMessageRef.current.innerHTML之前呈现每个被替换的FontAwesomeIcon组件?

xeufq47z

xeufq47z1#

我创造了三个州,

  • isEditing,跟踪用户是否正在编辑
  • editContent,用于用户编辑内容时
  • displayContent,用于在消息中显示转换后的内容

正如你所看到的,我已经删除了ref,但如果你需要它做其他事情,你显然可以把它加回去。
我们获取用户输入(文本),获取图标标签,并在**#**上拆分。然后我们Map拆分后的文本,并检查文本项是否是图标,如果是,则返回FontAwesomeIcon组件而不是文本。

function App() {
  const [editContent, setEditContent] = useState(
    "I would be so happy if #fa-face-smile# would be converted to the actual emoticon"
  );
  const [isEditing, setIsEditing] = useState(false);
  const [displayContent, setDisplayContent] = useState(null);

  function handleOnBlur(text) {
    // update the edit content
    setEditContent(text);
    // split the icon indicators
    const textAndIconLabels = text.split("#");
    // get the actual icons
    const icons = [...text.matchAll(/(?<=#)[a-z\-]+(?=#)/g)].flat();

    // loop over the textAndIconLabels
    const textAndIcons = textAndIconLabels.map((textOrIcon) => {
      // if the text is not a icon just return
      if (icons.includes(textOrIcon) === false) return textOrIcon;
      // if the text is a icon e.g. "fa-face-smile"
      return <FontAwesomeIcon icon={"fa-solid " + textOrIcon} />;
    });

    // update the displayContent
    setDisplayContent(textAndIcons);
    // set editing to false
    setIsEditing(false);
  }

  return (
    <div className="App">
      <div
        contentEditable="true"
        className={`form-control ${errors.message ? "is-invalid" : ""}`}
        onClick={() => setIsEditing(true)} // or focus
        onBlur={(e) => handleOnBlur(e.target.textContent)}
      >
        {isEditing ? editContent : <>{displayContent}</>}
      </div>
    </div>
  );
}

在这里看到一个live codesandbox

相关问题