【问题标题】:Add HTML tags dynamically using JSX使用 JSX 动态添加 HTML 标签
【发布时间】:2020-05-13 20:54:15
【问题描述】:
在下面的示例中,我想查找分隔符内的所有字符串 :;并在每个匹配项周围用 HTML 标记标记替换它们。如果它正常工作,由于 Mark 标签,这些字符串应该以黄色突出显示。相反,我的标签没有被扩展。有没有办法在 JSX 中做到这一点?
function App() {
let inputStr = 'This is a :test; of :highlighting;'
return (
<div>
{HighlightText(inputStr)}
</div>
);
}
function HighlightText(str) {
let MyTag = 'Mark';
var matches = str.split(/[:;]/);
let outputStr = '';
matches.forEach(m => {
const test = ':' + m + ';';
if (str.includes(test)) {
outputStr += <MyTag> + m + </MyTag>;
} else {
outputStr += m;
}
});
return outputStr;
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
【问题讨论】:
标签:
javascript
reactjs
jsx
【解决方案1】:
正如 cmets 中对另一个答案所说,出于安全考虑,我会避免使用 dangerouslySetInnerHTML。
相反,您可以将字符串分解为突出显示和未突出显示的子字符串数组,并将它们分别呈现为 <mark> 或常规 <span> 元素:
const { render } = ReactDOM,
rootNode = document.getElementById('root'),
testString = `This is a :test; of :highlighting;`
const App = () => {
const subStrings = testString.split(/(:.*?;)/)
return (
<div>
{
subStrings.map((s,key) =>
/(:.*;)/.test(s) ?
<mark {...{key}}>{s.slice(1,-1)}</mark> :
<span>{s}</span>
)
}
</div>
)
}
render (
<App />,
rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
【解决方案2】:
使用/:([^:;]*);/g 和String.prototype.split() 得到这样的数组:
["This is a ", "test", " of ", "highlighting", ""]
然后你可以使用Array.prototype.flatMap()这样分组:
[["This is a ", "test"], [" of ", "highlighting"], [""]]
最后你可以使用Array.prototype.map()为上面的每个内部数组返回一个<React.Fragment />:
ReactDOM.render(<App />, document.getElementById('react'));
function App() {
const inputStr = 'This is a :test; of :highlighting;';
return (
<div>{highlightText(inputStr)}</div>
);
}
function highlightText(str) {
const MyTag = 'Mark';
const matches = str.split(/:([^:;]*);/g);
const groups = matches.flatMap(
(value, index, array) => (
index % 2 === 0
? [array.slice(index, index + 2)]
: []
)
);
return groups.map(
([prefix, text], index) => (
<React.Fragment key={index}>
{prefix} {text && <MyTag>{text}</MyTag>}
</React.Fragment>
)
);
}
// example function demonstrating that `MyTag` resolves to `<Mark />`
function Mark({ children }) {
return (
<mark>{children}</mark>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>