J'essaie de mettre en surbrillance le texte correspondant à la requête, mais je ne sais pas comment obtenir les balises à afficher en HTML au lieu de texte.
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>
);
}
});
Sortie actuelle: script <strong> Java </strong>
Sortie souhaitée: Java script
Voici ma méthode simple d'aide 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>;
}
Il renvoie une plage, où les pièces demandées sont surlignées avec <b> </b>
Mots clés. Cela peut être simplement modifié pour utiliser une autre balise si nécessaire.
MISE À JOUR: Pour éviter un avertissement de clé unique manquante, voici une solution basée sur les étendues et la définition du style fontWeight pour les pièces correspondantes:
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>;
}
Il y a déjà un réagissez sur NPM pour faire ce que vous voulez:
var Highlight = require('react-highlighter');
[...]
<Highlight search={regex}>{name}</Highlight>
Voici un exemple de composant React qui utilise la norme <mark>
tag pour mettre un texte en surbrillance:
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>
)
}
Et voici comment l'utiliser
<Highlighted text="the quick brown fox jumps over the lazy dog" highlight="fox"/>
Par défaut, ReactJS échappe au HTML pour empêcher XSS. Si vous souhaitez définir du HTML, vous devez utiliser l'attribut spécial dangerouslySetInnerHTML
. Essayez le code suivant:
render: function() {
var name = "Javascript";
var query = "Java"
return (
<div>
<input type="checkbox" /> <span dangerouslySetInnerHTML={{__html: this._highlightQuery(name, query)}}></span>
</div>
);
}
Voici ma solution.
J'ai essayé de me concentrer sur la simplicité et les performances, j'ai donc évité les solutions qui impliquaient une manipulation manuelle du DOM en dehors de React, ou des méthodes dangereuses comme dangerouslySetInnerHTML
.
De plus, cette solution prend soin de combiner les correspondances suivantes en un seul <span/>
, évitant ainsi d'avoir des portées redondantes.
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>
Découvrez ceci codepen pour un exemple en direct.
Je vous suggère d'utiliser une approche différente. Créez un composant, disons <TextContainer />
, Qui contient des éléments <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;
Comme vous le voyez, le conteneur de texte contient comme état la requête actuelle. Maintenant, le composant <Text />
Pourrait ressembler à ceci:
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;
Ainsi, le composant racine a comme état, la requête en cours. Lorsque son état sera modifié, il déclenchera la méthode render()
des enfants. Chaque enfant recevra la nouvelle requête en tant que nouvel accessoire et affichera le texte, en mettant en évidence les parties qui correspondraient à la requête.
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>