Javascript 使用 ReactJS 突出显示文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29652862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Highlight text using ReactJS
提问by Andrew Hunt
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.
我试图突出显示与查询匹配的文本,但我不知道如何让标签显示为 HTML 而不是文本。
var Component = React.createClass({
_highlightQuery: function(name, query) {
var regex = new RegExp("(" + query + ")", "gi");
return name.replace(regex, "<strong></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
当前输出:<strong>Java</strong>脚本
Desired Output: Javascript
所需输出:Java脚本
回答by peter.bartos
Here is my simple twoliner helper method:
这是我的简单的 twoliner 辅助方法:
getHighlightedText(text, highlight) {
// Split text on highlight term, include term itself into parts, ignore case
const parts = text.split(new RegExp(`(${highlight})`, 'gi'));
return <span>{parts.map(part => part.toLowerCase() === highlight.toLowerCase() ? <b>{part}</b> : part)}</span>;
}
It returns a span, where the requested parts are highlighted with <b> </b>tags. This can be simply modified to use another tag if needed.
它返回一个跨度,其中请求的部分用<b> </b>标签突出显示。如果需要,可以简单地修改它以使用另一个标签。
UPDATE:To avoid unique key missing warning, here is a solution based on spans and setting fontWeight style for matching parts:
更新:为了避免唯一键丢失警告,这里有一个基于跨度和为匹配部分设置 fontWeight 样式的解决方案:
getHighlightedText(text, highlight) {
// Split on highlight term and include term into parts, ignore case
const parts = text.split(new RegExp(`(${highlight})`, 'gi'));
return <span> { parts.map((part, i) =>
<span key={i} style={part.toLowerCase() === highlight.toLowerCase() ? { fontWeight: 'bold' } : {} }>
{ part }
</span>)
} </span>;
}
回答by Henok T
Here is an example of a react component that uses the standard <mark>tag to highlight a text:
下面是一个使用标准<mark>标签突出显示文本的 react 组件示例:
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"/>
回答by aij
There is already a react component on NPMto do what you want:
var Highlight = require('react-highlighter');
[...]
<Highlight search={regex}>{name}</Highlight>
回答by Yanik Ceulemans
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:
默认情况下,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>
);
}
回答by Yaroslav Shugailo
const escapeRegExp = (str = '') => (
str.replace(/([.?*+^$[\]\(){}|-])/g, '\')
);
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>
回答by Yoav Kadosh
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.
我试图专注于简单性和性能,所以我避免了涉及在 React 之外手动操作 DOM 的解决方案,或者像dangerouslySetInnerHTML.
Additionally, this solution takes care of combining subsequent matches into a single <span/>, thus avoiding having redundant spans.
此外,此解决方案负责将后续匹配项合并为单个<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>;
};
Usage:
用法:
<Highlighter highlight='text'>Some text to be highlighted</Highlighter>
Check out this codepenfor a live example.
查看此代码笔以获取实时示例。
回答by user3713526
Mark matches as a function https://codesandbox.io/s/pensive-diffie-nwwxe?file=/src/App.js
将匹配标记为函数 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;
回答by gcedo
I would suggest you use a different approach. Create one component, say <TextContainer />, which contains <Text />elements.
我建议你使用不同的方法。创建一个组件,例如<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;
As you see the text container holds as state the current query. Now, the <Text />component could be something like this:
如您所见,文本容器将当前查询作为状态保存。现在,<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;
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.
因此,根组件具有状态,即当前查询。当它的状态改变时,它会触发孩子的render()方法。每个孩子将接收新查询作为新道具,并输出文本,突出显示与查询匹配的部分。
回答by Cristik
This should work:
这应该有效:
var Component = React.createClass({
_highlightQuery: function(name, query) {
var regex = new RegExp("(" + query + ")", "gi");
return "<span>"+name.replace(regex, "<strong></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.
基本上,您正在即时生成反应组件。如果需要,您可以将<span>标签放在render()函数内,而不是将标签放在函数内_highlightQuery()。

