我显示存储在数据库中的文本。数据来自firebase作为字符串(包括换行符)。为了使其显示为HTML,我最初做了以下内容:
<p className="term-definition"
dangerouslySetInnerHTML={{__html: (definition.definition) ? definition.definition.replace(/(?:\r\n|\r|\n)/g, '<br />') : ''}}></p>
这很有效。然而,还有一个额外的功能。用户可以键入[word]
,该字词将被链接。为了实现这一点,我创建了以下函数:
parseDefinitionText(text){
text = text.replace(/(?:\r\n|\r|\n)/g, '<br />');
text = text.replace(/\[([A-Za-z0-9'\-\s]+)\]/, function(match, word){
// Convert it to a permalink
return (<Link to={'/terms/' + this.permalink(word) + '/1'}>{word}</Link>);
}.bind(this));
return text;
},
我遗漏了this.permalink
方法,因为它不相关。正如您所看到的,我尝试返回从react-router导入的<Link>
组件。但是,由于它是原始HTML,dangerouslySetInnerHTML
不再正常工作。
所以我有点卡在这一点上。我可以做什么来格式化内部文本并创建链接?
答案 0 :(得分:2)
您可以将文本拆分为Links +字符串数组,如下所示:
import {Link} from 'react-router';
const paragraphWithLinks = ({markdown}) => {
const linkRegex = /\[([\w\s-']+)\]/g;
const children = _.chain(
markdown.split(linkRegex) // get the text between links
).zip(
markdown.match(linkRegex).map( // get the links
word => <Link to={`/terms/${permalink(word)}/1`}>{word}</Link> // and convert them
)
).flatten().thru( // merge them
v => v.slice(0, -1) // remove the last element (undefined b/c arrays are different sizes)
).value();
return <p className='term-definition'>{children}</p>;
};
这种方法的最佳之处在于无需使用dangerouslySetInnerHTML
。使用它通常是非常糟糕的主意,因为您可能会创建XSS漏洞。例如,这可能使黑客窃取用户的登录凭据。
在大多数情况下,您不需要使用dangerouslySetHTML
。明显的例外是与第三方库集成,仍应仔细考虑。
答案 1 :(得分:0)
我遇到了类似的情况,但是接受的解决方案对我来说不是一个可行的选择。
我以相当粗暴的方式使用react-dom
。我将组件设置为侦听点击事件,如果点击的类别为react-router-link
。发生这种情况时,如果项目具有data-url
属性集,则使用browserHistory.push
。我目前正在使用同构应用,这些点击事件对服务器生成没有意义,所以我只是有条件地设置这些事件。
这是我使用的代码:
import React from 'react';
import _ from 'lodash';
import { browserHistory } from 'react-router'
export default class PostBody extends React.Component {
componentDidMount() {
if(! global.__SERVER__) {
this.listener = this.handleClick.bind(this);
window.addEventListener('click', this.listener);
}
}
componentDidUnmount() {
if(! global.__SERVER__) {
window.removeEventListener("scroll", this.listener);
}
}
handleClick(e) {
if(_.includes(e.target.classList, "react-router-link")) {
window.removeEventListener("click", this.listener);
browserHistory.push(e.target.getAttribute("data-url"));
}
}
render() {
function createMarkup(html) { return {__html: html}; };
return (
<div className="col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-3 col-lg-8 col-lg-offset-2 post-body">
<div dangerouslySetInnerHTML={createMarkup(this.props.postBody)} />
</div>
);
}
}
希望这会有所帮助!