2

我正在显示存储在数据库中的文本。数据来自 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方法,因为它不相关。如您所见,我正在尝试返回<Link>从 react-router 导入的组件。但是,由于它是原始 HTML,dangerouslySetInnerHTML因此不再正常工作。

所以我有点卡在这一点上。我可以做些什么来格式化内部文本并创建链接?

4

2 回答 2

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. 明显的例外是与第 3 方库的集成,仍应仔细考虑。

于 2015-11-16T04:36:53.893 回答
1

我遇到了类似的情况,但是接受的解决方案对我来说不是一个可行的选择。

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>
    );
  }

}

希望这会有所帮助!

于 2016-10-06T19:58:42.907 回答