在 react-contenteditable 中渲染 JSX 元素

Render JSX element in react-contenteditable

react-contenteditable中,html属性只接受string,我如何设法在字符串中添加带有eventlistener的JSX元素。

Sandbox

import ContentEditable from "react-contenteditable";
import "./styles.css";

const text = "I want to order cheese chicken pizza.";

const Elems = {
  cheese: (
    <span style={{ color: "red" }} onClick={() => alert("clicked cheese span")}>
      cheese
    </span>
  ),
  chicken: (
    <span
      style={{ color: "red" }}
      onClick={() => alert("clicked chicken span")}
    >
      chicken
    </span>
  )
};

export default function App() {
  const swapText = () => {
    const text_array = text.split(" ");
    console.log(text_array);
    const a = text_array.map((item) => {
      if (item in Elems) item = Elems[item];
      else item += " ";
      return item;
    });
    return a;
  };

  return (
    <div className="App">
      <h2>React contenteditable</h2>
      <ContentEditable html={swapText()} />
    </div>
  );
}

您可以使用 ReactDOMServer.renderToStaticMarkup(element) 将 React 元素转换为标记。这对样式有帮助,但对点击处理程序没有帮助:

if (item in Elems) item = renderToStaticMarkup(Elems[item]);

要使项目可点击,您需要将 onClick 处理程序传递给 <ContentEditable> 组件(或其父组件):

<ContentEditable onClick={handleClick} html={swapText()} />

您还需要确定可点击的元素。在这个例子中,我为它们都添加了 data-action 标签:

const Elems = {
  cheese: (
    <span style={{ color: 'red' }} data-action="cheese">
      cheese
    </span>
  ),
  chicken: (
    <span style={{ color: 'red' }} data-action="chicken">
      chicken
    </span>
  )
};

点击处理程序使用 Element.closest() 搜索事件目标或具有 data-action 标签的父级,如果它找到一个,它将作用于标签值:

const handleClick = (e) => {
  const target = e.target.closest('[data-action]');

  if (!target) return;

  const action = target.dataset.action;

  alert(action);
};

工作示例 - sandbox