问题
I'm trying to highlight text matching the query but I can't figure out how to get the tags to display as HTML instead of text.
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>
);
}
});
Current Output: <strong>Java</strong>script
Desired Output: Javascript
回答1:
Here is my simple twoliner helper method:
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>;
}
It returns a span, where the requested parts are highlited with <b> </b>
tags. This can be simply modified to use other tag if needed.
UPDATE: To avoid unique key missing warning, here is a solution based on spans and setting fontWeight style for matching parts:
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>;
}
回答2:
There is already a react component on NPM to do what you want:
var Highlight = require('react-highlighter');
[...]
<Highlight search={regex}>{name}</Highlight>
回答3:
Here is an example of a react component that uses the standard <mark>
tag to highlight a text:
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>
)
}
And here is how to use it
<Highlighted text="the quick brown fox jumps over the lazy dog" highlight="fox"/>
回答4:
By default ReactJS escapes HTML to prevent XSS. If you do wish to set HTML you need to use the special attribute dangerouslySetInnerHTML
.
Try the following code:
render: function() {
var name = "Javascript";
var query = "java"
return (
<div>
<input type="checkbox" /> <span dangerouslySetInnerHTML={{__html: this._highlightQuery(name, query)}}></span>
</div>
);
}
回答5:
I would suggest you use a different approach. Create one component, say <TextContainer />
, which contains <Text />
elements.
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;
As you see the text container holds as state the current query. Now, the <Text />
component could be something like this:
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;
So, the root component has as state, the current query. When its state will be changed, it will trigger the children's render()
method. Each child will receive the new query as a new prop, and output the text, highlighting those parts that would match the query.
回答6:
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>
回答7:
Here's my solution.
I tried to focus on simplicity and performance, so I avoided solutions that involved manual manipulation of the DOM outside of React, or unsafe methods like dangerouslySetInnerHTML
.
Additionally, this solution takes care of combining subsequent matches into a single <span/>
, thus avoiding having redundant spans.
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>;
};
Usage:
<Highlighter highlight='text'>Some text to be highlighted</Highlighter>
Check out this codepen for a live example.
回答8:
This should work:
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>
);
}
});
Basically you're generating a react component on the fly. If you want, you can put the <span>
tag inside the render()
function rather then the _highlightQuery()
one.
来源:https://stackoverflow.com/questions/29652862/highlight-text-using-reactjs