Невозможно изменить дочерние элементы в разобранном 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>
);
};