使用ReactJS突出显示文本

时间:2015-04-15 14:22:22

标签: javascript reactjs react-jsx

我正在尝试突出显示与查询匹配的文字,但我无法弄清楚如何将标记显示为HTML而不是文本。

var Component = React.createClass({
    _highlightQuery: function(name, query) {
        var regex = new RegExp("(" + query + ")", "gi");
        return name.replace(regex, "<strong>$1</strong>");
    },
    render: function() {
        var name = "Javascript";
        var query = "java"
        return (
            <div>
                <input type="checkbox" /> {this._highlightQuery(name, query)}
            </div>
        );
    }
});

当前输出:&lt; strong&gt; Java&lt; / strong&gt;脚本

所需输出: Java 脚本

10 个答案:

答案 0 :(得分:30)

这是我简单的twoliner辅助方法:

getHighlightedText(text, higlight) {
    // Split text on higlight term, include term itself into parts, ignore case
    var parts = text.split(new RegExp(`(${higlight})`, 'gi'));
    return <span>{parts.map(part => part.toLowerCase() === higlight.toLowerCase() ? <b>{part}</b> : part)}</span>;
}

它返回一个范围,其中所请求的部分与<b> </b>标签一起高亮显示。如果需要,可以简单地修改它以使用其他标记。

更新:为了避免唯一键缺失警告,这里有一个基于跨度的解决方案,并为匹配的部分设置fontWeight样式:

getHighlightedText(text, higlight) {
    // Split on higlight term and include term into parts, ignore case
    let parts = text.split(new RegExp(`(${higlight})`, 'gi'));
    return <span> { parts.map((part, i) => 
        <span key={i} style={part.toLowerCase() === higlight.toLowerCase() ? { fontWeight: 'bold' } : {} }>
            { part }
        </span>)
    } </span>;
}

答案 1 :(得分:4)

已经有react component on NPM可以做你想做的事了:

var Highlight = require('react-highlighter');
[...]
<Highlight search={regex}>{name}</Highlight>

答案 2 :(得分:3)

默认情况下,ReactJS会转义HTML以阻止XSS。如果您确实希望设置HTML,则需要使用特殊属性dangerouslySetInnerHTML。 请尝试以下代码:

render: function() {
        var name = "Javascript";
        var query = "java"
        return (
            <div>
                <input type="checkbox" /> <span dangerouslySetInnerHTML={{__html: this._highlightQuery(name, query)}}></span>
            </div>
        );
    }

答案 3 :(得分:2)

以下是使用标准<mark>标记突出显示文字的反应组件示例:

const Highlighted = ({text = '', highlight = ''}) => {
   if (!highlight.trim()) {
     return <span>{text}</span>
   }
   const regex = new RegExp(`(${_.escapeRegExp(highlight)})`, 'gi')
   const parts = text.split(regex)
   return (
     <span>
        {parts.filter(part => part).map((part, i) => (
            regex.test(part) ? <mark key={i}>{part}</mark> : <span key={i}>{part}</span>
        ))}
    </span>
   )
}

以下是如何使用它

<Highlighted text="the quick brown fox jumps over the lazy dog" highlight="fox"/>

答案 4 :(得分:0)

我建议你使用不同的方法。创建一个组件,例如<TextContainer />,其中包含<Text />个元素。

var React = require('react');
var Text = require('Text.jsx');

var TextContainer = React.createClass({
    getInitialState: function() {
        return {
            query: ''
        };
    },
    render: function() {
        var names = this.props.names.map(function (name) {
            return <Text name={name} query={this.state.query} />
        });
        return (
            <div>
                {names}
           </div>
        );
    }
});

module.exports = TextContainer;

如您所见,文本容器保持当前查询的状态。现在,<Text />组件可能是这样的:

var React = require('react');

var Text = React.createClass({
    propTypes: {
        name: React.PropTypes.string.isRequired,
        query: React.PropTypes.string.isRequired
    },

    render: function() {
        var query = this.props.query;
        var regex = new RegExp("(" + query + ")", "gi");
        var name = this.props.name;
        var parts = name.split(regex);
        var result = name;

        if (parts) {
            if (parts.length === 2) {
                result =
                    <span>{parts[0]}<strong>{query}</strong>{parts[1]}</span>;
            } else {
                if (name.search(regex) === 0) {
                    result = <span><strong>{query}</strong>{parts[0]}</span>
                } else {
                    result = <span>{query}<strong>{parts[0]}</strong></span>
                }
            }
        }

        return <span>{result}</span>;
    }

});

module.exports = Text;

因此,根组件具有当前查询的状态。当状态改变时,它将触发孩子的render()方法。每个孩子将接收新查询作为新道具,并输出文本,突出显示与查询匹配的那些部分。

答案 5 :(得分:0)

  const escapeRegExp = (str = '') => (
    str.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1')
  );

  const Highlight = ({ search = '', children = '' }) => {
    const patt = new RegExp(`(${escapeRegExp(search)})`, 'i');
    const parts = String(children).split(patt);

    if (search) {
      return parts.map((part, index) => (
        patt.test(part) ? <mark key={index}>{part}</mark> : part
      ));
    } else {
      return children;
    }
  };

  <Highlight search="la">La La Land</Highlight>

答案 6 :(得分:0)

这是我的解决方法。

我试图将重点放在简单性和性能上,所以避免使用涉及在React之外手动操作DOM或诸如dangerouslySetInnerHTML之类的不安全方法的解决方案。

此外,此解决方案还负责将后续匹配项合并为一个<span/>,从而避免了多余的跨度。

const Highlighter = ({children, highlight}) => {
  if (!highlight) return children;
  const regexp = new RegExp(highlight, 'g');
  const matches = children.match(regexp);
  console.log(matches, parts);
  var parts = children.split(new RegExp(`${highlight.replace()}`, 'g'));

  for (var i = 0; i < parts.length; i++) {
    if (i !== parts.length - 1) {
      let match = matches[i];
      // While the next part is an empty string, merge the corresponding match with the current
      // match into a single <span/> to avoid consequent spans with nothing between them.
      while(parts[i + 1] === '') {
        match += matches[++i];
      }

      parts[i] = (
        <React.Fragment key={i}>
          {parts[i]}<span className="highlighted">{match}</span>
        </React.Fragment>
      );
    }
  }
  return <div className="highlighter">{parts}</div>;
};

用法:

<Highlighter highlight='text'>Some text to be highlighted</Highlighter>

查看此codepen以获取实时示例。

答案 7 :(得分:0)

将标记匹配为函数 https://codesandbox.io/s/pensive-diffie-nwwxe?file=/src/App.js

import React from "react";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      res: "Lorem ipsum dolor"
    };
    this.markMatches = this.markMatches.bind(this);
  }
  markMatches(ev) {
    let res = "Lorem ipsum dolor";
    const req = ev.target.value;
    if (req) {
      const normReq = req
        .toLowerCase()
        .replace(/\s+/g, " ")
        .trim()
        .split(" ")
        .sort((a, b) => b.length - a.length);
      res = res.replace(
        new RegExp(`(${normReq.join("|")})`, "gi"),
        match => "<mark>" + match + "</mark>"
      );
    }
    this.setState({
      res: res
    });
  }

  render() {
    return (
      <div className="App">
        <input type="text" onChange={this.markMatches} />
        <br />
        <p dangerouslySetInnerHTML={{ __html: this.state.res }} />
      </div>
    );
  }
}

export default App;

答案 8 :(得分:0)

我需要在包含 HTML 标签的评论中进行搜索。

例如:我的评论之一看起来像下面的例子

你好世界

<div>Hello<strong>World</strong></div>

所以,我想在所有这些评论中进行搜索并突出显示搜索结果。

众所周知,我们可以使用 HTML 标签 <mark>

所以。我创建了一个辅助函数,它执行在文本中添加 <mark> 标记(如果它包含搜索的文本)的任务。

getHighlightedText = (text, highlight) => {
    if (!highlight.trim()) {
      return text;
    }
    const regex = new RegExp(`(${highlight})`, "gi");
    const parts = text.split(regex);
    const updatedParts = parts
      .filter((part) => part)
      .map((part, i) =>
        regex.test(part) ? <mark key={i}>{part}</mark> : part
      );
    let newText = "";
    [...updatedParts].map(
      (parts) =>
        (newText =
          newText +
          (typeof parts === "object"
            ? `<${parts["type"]}>${highlight}</${parts["type"]}>`
            : parts))
    );
    return newText;
  };

因此,我们必须将函数内的文本和搜索文本作为参数传递。

输入

getHighlightedText("<div>Hello<strong>World</strong></div>", "hello")

输出

<div><mark>Hello</mark><strong>World</strong></div>

如果在解决方案方面需要更多帮助,请告诉我。

答案 9 :(得分:-1)

这应该有效:

var Component = React.createClass({
    _highlightQuery: function(name, query) {
        var regex = new RegExp("(" + query + ")", "gi");
        return "<span>"+name.replace(regex, "<strong>$1</strong>")+"</span>";
    },
    render: function() {
        var name = "Javascript";
        var query = "java"
        return (
            <div>
                <input type="checkbox" />{JSXTransformer.exec(this._highlightQuery(name, query))}
            </div>
        );
    }
});

基本上你是在动态生成反应组件。如果需要,可以将<span>标记放在render()函数中,而不是_highlightQuery()