Невозможно изменить дочерние элементы в разобранном HTML

Я хочу сделать большой кусок HTML, заменив определенные теги, такие как <p> а также <a> с компонентами React (т.е. <StyledParagraph> а также <StyledLink>)

Я протестировал много библиотек, включая html-реагировать-парсер. В отличие от многих других, в html-response-parser есть пример, который отвечает моим потребностям. Но я не могу заставить пример работать. (Использование React 16.5.3)

const test = () =>
  <>
    {parse(
      `
      <p id="main">
        <span class="prettify">
          keep me and make me pretty!
        </span>
      </p>
    `,
      {
        replace: ({ attribs, children }) => {
          if (!attribs) return;

          if (attribs.id === 'main') {
            return (
              <h1 style={{ fontSize: 42 }}>
                {domToReact(children)}
              </h1>
            );
          } else if (attribs.class === 'prettify') {
            return (
              <span style={{ color: 'hotpink' }}>
                {domToReact(children)}
              </span>
            );
          }
        }
      }
    )}
  </>

Я не прошла parserOptions к domToReact функция, потому что я еще не нашел документацию для этих опций.

Ожидаемые результаты:

<h1 style="font-size:42px">
  <span style="color:hotpink">keep me and make me pretty!</span>
</h1>

Пока я не могу изменить вложенные узлы (в этом случае <span>).

Фактические результаты:

<h1 style="font-size: 42px;">
    <span class="prettify">keep me and make me pretty!</span>
  </h1>

2 ответа

Вы должны пройти replace функция к domToReact как часть его options пары. Из источника:

/**
 * Converts DOM nodes to React elements.
 *
 * @param  {Array}    nodes             - The DOM nodes.
 * @param  {Object}   [options]         - The additional options.
 * @param  {Function} [options.replace] - The replace method.
 * @return {ReactElement|Array}
 */

В случае этого примера это будет означать...

function replaceHtmlWithReact({ attribs, children }) {
  if (!attribs) return;

  if (attribs.id === 'main') {
    return (
      <h1 style={{ fontSize: 42 }}>
        {domToReact(children, { replace: replaceHtmlWithReact })}
      </h1>
    );
  } else if (attribs.class === 'prettify') {
    return (
      <span style={{ color: 'hotpink' }}>
        {domToReact(children, { replace: replaceHtmlWithReact })}
      </span>
    );
  }
}

const test = () => 
<>
  {parse(
    `
      <p id="main">
        <span class="prettify">
          keep me and make me pretty!
        </span>
      </p>
    `,{ replace: replaceHtmlWithReact }
  )}
</>

У меня это работает без domToReactвариант. Я передаю строку HTML из объекта JSON, полученного из Wordpress, в react-syntax-highlighter. Я еще не изучал исходный код, чтобы увидеть, в чем разница между их использованием, но замена тега HTML на JSX, похоже, работает с domNode.attribs просто хорошо.

Этот компонент принимает этот объект JSON (который состоит из сообщений Wordpress), сопоставляет каждое сообщение с отдельным анализируемым разделом, а затем заменяет каждый pre тега каждого проанализированного раздела, отвечающего определенным критериям (в данном случае class=wp-block-code или же class=CodeMirror) с JSX SyntaxHighlighter тег, сохраняя при этом текст кодового блока ( domNode.children[0].data).

Примечания: Анализируя объект JSON, я обнаружил, что ни один из этих domNode.children массивы имели более одной позиции, поэтому позиция [0] было все, что требовалось в моем случае - очевидно, что ваши потребности могут отличаться.

Ни одна из команд от html-react-parser или объекты JSON, полученные из Wordpress, деструктурируются, поэтому вы можете видеть четкое разграничение API / команд.

      import parse from 'html-react-parser';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { gruvboxDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';

export const Blog = (props) => {
  return (
    <div>
      <h1>This is an example of a blog component</h1>
      <div>
        {props.posts.map((post, index) => (
          <div key={post.id}>
            <h3>{post.id}</h3>
            <div>{parse(post.title.rendered)}</div>
            <div>{parse(post.excerpt.rendered)}</div>
            <div>
              {parse(post.content.rendered, {
                replace: (domNode) => {
                  if (
                    (domNode.attribs && domNode.attribs.class === 'CodeMirror') ||
                    (domNode.attribs && domNode.attribs.class === 'wp-block-code')
                  ) {
                    return (
                      <SyntaxHighlighter
                        language="bash"
                        showLineNumbers={true}
                        style={gruvboxDark}
                        wrapLongLines={true}
                      >
                        {domNode.children[0].data}
                      </SyntaxHighlighter>
                    );
                  }
                },
              })}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};
Другие вопросы по тегам