如何渲染包含html标签元素的字符串
最近有个搜索替换的需求,用户可以输入关键字信息来匹配出对应的数据,然后对其关键字进行标记显示,如下图所示:
实现上面的需求的思路就是前端去判断检索内容,将内容中对应的关键字设置一个背景颜色的样式,代码如下:
if (content?.includes(serachV)) {
content = content.replaceAll(serachV, `<span style="background-color: gold;">${serachV}</span>`);
return content
}
但这样设置后并未达到我想要的效果,前端展示上并没有变黄,没有生效。
后面查阅资料发现,在react中,出于安全考虑的原因(XSS 攻击),在 React.js 当中所有的表达式插入的内容都会被自动转义,就相当于 jQuery 里面的 text(…) 函数一样,任何的 HTML 格式都会被转义掉。
所以通过富文本编辑器进行操作后的内容,会保留原有的标签样式,并不能正确展示,如下图红框所示:
因此我们可以使用dangerouslySetInnerHTML
这个api将其设置为内部的HTML,以此达到上述的效果,代码如下:
if (content?.includes(serachV)) {
content = content.replaceAll(serachV, `<span style="background-color: gold;">${serachV}</span>`);
return <span dangerouslySetInnerHTML={{ __html: content }} />;
}
完整代码如下:
export const quickReplaceColumns = (serachV: string) => {
const renderNode = (content: string) => {
if (content?.includes(serachV)) {
content = content.replaceAll(serachV, `<span style="background-color: gold;">${serachV}</span>`);
return <span dangerouslySetInnerHTML={{ __html: content }} />;
}
return content || '--';
};
return [
{
title: '用例名称',
dataIndex: 'name',
width: '30%',
render: (name: string) => renderNode(name),
},
{
title: '用例内容',
dataIndex: 'content',
width: '50%',
render: (content: string) => renderNode(content),
},
{
title: '所属模块',
dataIndex: 'module_name',
width: '10%',
},
];
};
实现效果如下:
dangerouslySetInnerHTML是什么
dangerouslySetInnerHTMl 是React标签的一个属性,dangerouslySetInnerHTML翻译过来就是:危险的设置内部HTML。
为什么说是危险的呢?因为用户的输入是不可控的,如果是这样的操作是开发给用户输入可能会导致 cross-site scripting (XSS) 攻击或者其他网页攻击,还有一些意向不到的错误出现。
但我们这里的使用情况是控制了输入的,并没有开放给用户输入,所以不会出现上面的情况,可以放心使用。
使用注意事项
- dangerouslySetInnerHTML的语法:第一层{ }代表JSX语法,第二层{ }是一个__html:string的键值对。
- 最初未用反引号包裹
<img className="detail_img" src=${v[0]} />
结果渲染的全是[object Object],想了半天才反应过来__html:string
- 用反引号包裹的html代码不再是JSX语法,所以clasName要改为class;