我有这段代码显然不起作用:
_.each(matches, (match) ->
string = string.replace(match, ->
<span className="match" key={i++}>{match}</span>
)
)
因为这会导致字符串与对象混合。 不好我知道。 但是如何在字符串中添加 React 组件呢? 我想要的只是用反应组件突出显示字符串的一部分。 我猜这是一个很难破解的案例。
这样的事情应该工作:
const escapeRE = new RegExp(/([.*+?^=!:$(){}|[\]\/\\])/g)
const safeRE = (string) => {
return string.replace(escapeRE, "\\$1")
}
class Hightlight extends Component {
static propTypes = {
match : PropTypes.string,
string : PropTypes.string,
}
render() {
return (
<span
dangerouslySetInnerHTML={{
__html : string.replace(safeRE(this.props.match), "<strong className\"match\">$1</strong>")
}} />
)
}
}
是的,我一直在考虑滥用dangerouslySetInnerHTML
但我不喜欢这个想法。 这种方法有充分的理由被标记为危险。
有没有办法教 React 解析字符串中的 jsx? 让 React 解析 iE
var example = "this one word <span className="match" key={i++}>hello</span> is highlighted"
并在渲染方法中返回它?
@binarykitchen您可以动态构造 React 元素,这就是您在此处需要做的,仅用字符串替换是无法做到的。
@syranide是的,我已经知道了。 我的观点是:这不是一个很好的 JSX/React 特性吗? 解析一个字符串并将其中的任何标签转换为子 React 组件。
您可以将split
函数与正则表达式一起使用,然后替换捕获的部分,如下所示:
var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
parts[i] = <span className="match" key={i}>{parts[i]}</span>;
}
return <div>{parts}</div>;
如果这不清楚,请告诉我。
在运行时解析 JSX 容易出错且速度缓慢,并且很容易产生安全隐患——它本质上不会比危险的 SetInnerHTML 更安全。
这可能是类型案例的一个问题
— 毫升
在12个火星2015年,在21:37,本·阿尔珀特[email protected]写道:
您可以使用带有正则表达式的 split 函数,然后替换捕获的部分,如下所示:
var parts = "我是一头牛;牛说哞哞。MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i <parts.length; i += 2) {
零件[i] = ;}返回{部分};
如果这不清楚,请告诉我。—
直接回复此邮件或在 GitHub 上查看。
我在尝试以编程方式突出显示部分字符串时也遇到了这个问题(即用<span>
标签替换)。 我最终根据上面的@spicyj的解决方案创建了一个模块。 对于任何感兴趣的人: iansinnott/react-string-replace
@iansinnott感谢分享。 我开始使用它然后意识到我将需要完整的String.prototype.replace
API(需要访问各个匹配组以获取替换函数中的正则表达式)。 我意识到更改不仅仅是一个简单的补丁(并且需要更改 API),因此我创建了一个新的存储库: https :
如果react-string-replace
不符合您的要求:
以下内容对我有用,可以突出显示文本字符串中的关键字,而无需
危险地设置 HTML:
/**
* Find and highlight relevant keywords within a block of text
* <strong i="7">@param</strong> {string} label - The text to parse
* <strong i="8">@param</strong> {string} value - The search keyword to highlight
* <strong i="9">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
*/
const formatLabel = (label, value) => {
if (!value) {
return label;
}
return (<span>
{ label.split(value)
.reduce((prev, current, i) => {
if (!i) {
return [current];
}
return prev.concat(<b key={value + current}>{ value }</b>, current);
}, [])
}
</span>);
};
formatLabel('Lorem ipsum dolor sit amet', 'dolor');
// <span>Lorem ipsum <b>dolor</b> sit amet</span>
我需要这样的东西来匹配某个模式的提及,以便它可以包装多个值并对@richardwestenra解决方案进行一些更改。 也许它对某人有用。
/**
* Find and highlight mention given a matching pattern within a block of text
* <strong i="7">@param</strong> {string} text - The text to parse
* <strong i="8">@param</strong> {array} values - Values to highlight
* <strong i="9">@param</strong> {RegExp} regex - The search pattern to highlight
* <strong i="10">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
*/
const formatMentionText = (text, values, regex) => {
if (!values.length)
return text;
return (<div>
{text.split(regex)
.reduce((prev, current, i) => {
if (!i)
return [current];
return prev.concat(
values.includes(current) ?
<mark key={i + current}>
{current}
</mark>
: current
);
}, [])}
</div>);
};
const text = 'Lorem ipsum dolor sit amet [[Jonh Doe]] and [[Jane Doe]]';
const values = ['Jonh Doe', 'Jane Doe'];
const reg = new RegExp(/\[\[(.*?)\]\]/); // Match text inside two square brackets
formatMentionText(text, values, reg);
// Lorem ipsum dolor sit amet <mark>Jonh Doe</mark> and <mark>Jane Doe</mark>
我有一个类似的问题,我用反应门户解决了它,为了轻松找到节点,我用 div 替换了字符串,并使用 createPortal 将我的反应组件渲染到该 div 中。
@rmtngh我很好奇你为什么需要这样做。 看起来它可能有点矫枉过正。 你在交错非反应代码吗?
关于这个问题的解决方案,我想再次推荐string-replace-to-array
(我是作者)。 它已经在多个环境中进行了战斗和时间测试。 它也很小(整个库就是这个文件 https://github.com/oztune/string-replace-to-array/blob/master/string-replace-to-array.js)。
这是正则表达式的使用示例:
import replace from 'string-replace-to-array'
// The API is designed to match the native 'String.replace',
// except it can handle non-string replacements.
replace(
'Hello Hermione Granger...',
/(Hermione) (Granger)/g,
function (fullName, firstName, lastName, offset, string) {
return <Person firstName={ firstName } lastName={ lastName } key={ offset } />
}
)
// output: ['Hello ', <Person firstName="Hermione" lastName="Granger" key={ 0 } />, ...]
@oztune感谢您的回复,在这种情况下,我有一个来自 CMS 所见即所得编辑器的 html 标记字符串,我想在该标记内的某些位置放置反应组件。
您认为使用库而不是使用门户会更好吗? 我认为门户所做的只是在另一个节点内渲染组件而不是最近的节点,这不会比渲染普通组件更昂贵,唯一的额外步骤是替换可以用原生 js 替换完成的字符串。
我错过了什么吗? 改用图书馆会有什么好处吗?
@rmtngh我想说这取决于你想要做什么。 如果你只是想在你的 DOM 树的不同区域散布一些 React 组件,并且树还没有被 React 渲染,那么门户就是你要走的路。 当您尝试替换的部分已经在 React 组件中呈现时,我提到的方法最有用。
这是返回给定文本和模式的节点数组的代码:
const highlightPattern = (text, pattern) => {
const splitText = text.split(pattern);
if (splitText.length <= 1) {
return text;
}
const matches = text.match(pattern);
return splitText.reduce((arr, element, index) => (matches[index] ? [
...arr,
element,
<mark>
{matches[index]}
</mark>,
] : [...arr, element]), []);
};
谢谢@wojtekmaj
我的模式组版本:
const replacePatternToComponent = (text, pattern, Component) => {
const splitText = text.split(pattern);
const matches = text.match(pattern);
if (splitText.length <= 1) {
return text;
}
return splitText.reduce((arr, element) => {
if (!element) return arr;
if(matches.includes(element)) {
return [...arr, Component];
}
return [...arr, element];
},
[]
);
};
const string = 'Foo [first] Bar [second]';
const pattern = /(\[first\])|(\[second\])/g;
replacePatternToComponent(string, pattern, <Component />);
使用打字稿的方法:
const formatString = (
str: string,
formatingFunction?: (value: number | string) => React.ReactNode,
...values: Array<number | string>
) => {
const templateSplit = new RegExp(/{(\d)}/g);
const isNumber = new RegExp(/^\d+$/);
const splitedText = str.split(templateSplit);
return splitedText.map(sentence => {
if (isNumber.test(sentence)) {
const value = values[Number(sentence)];
return Boolean(formatingFunction) ? formatingFunction(value) : value;
}
return sentence;
});
};
使用示例:
const str = '{0} test {1} test';
formatString(str, value => <b>{value}</b>, value1, value2);
结果:
<b>value1</b> test <b>value2</b> test
@rmtngh您能否提供一个示例,说明您如何通过 createportal 实现标记丰富? 我也在做同样的事情。
@Dashue这个想法是在你的标记中为你的反应组件创建一些目标,这取决于 HTML 字符串以及你对它的控制程度,
如果您可以在服务器端更改它,您可能需要为您的元素提供一个 ID。 就像是 :
<div id="component_target_1"></div>
在 react 中,使用正则表达式查找\id="(component_target_\d)"\g
,存储 ids (state.targets) 并渲染您的组件:
let mappedComponents
if(this.state.targets && this.state.targets.length){
mappedComponents = this.state.targets.map((id,index)=><MyComponent id={id} key={id} />)
}
这是“MyComponent”的示例:
import React from 'react'
import ReactDOM from 'react-dom'
export default class MyComponent extends React.Component {
constructor(props) {
super(props)
}
getWrapper(){
return document.getElementById(this.props.id)
}
render() {
if(!this.getWrapper()) return null
const content = <div>
Hello there! I'm rendered with react.
</div>
return ReactDOM.createPortal(
content,
this.getWrapper(),
);
}
}
如果您对 HTML 字符串没有太多控制权,您仍然可以使用相同的方法,您可能需要找到一些元素并将目标元素注入字符串。
伟大的线程家伙!
我创建了一个简单的React Text Highlighter笔,它实现了这个线程中的一些想法(还有一些额外的魔法......),希望未来的访问者会发现它很有用。
这是使用map
的解决方案,
在此处分叉@sophiebits解决方案:
const reg = new RegExp(/(\bmoo+\b)/, 'gi');
const parts = text.split(reg);
return <div>{parts.map(part => (part.match(reg) ? <b>{part}</b> : part))}</div>;
美丽的解决方案@rehat101
这是在我的情况下最有效的方法 - 按空格字符拆分并查找特定单词。
HTML 中有点乱,但谁在乎 😂
💗 RegExp和map使这一切变得如此干净。 💗💗💗
const Speech = ({ speech, speeches, setSpeeches, i, text }) => {
const highlightRegExp = new RegExp(
/you|can|do|it|puedes|hacerlo|pingüinos|son|bellos/,
"gi"
);
const delineator = " ";
const parts = text.split(delineator);
return (
<div>
{parts.map(part =>
part.match(highlightRegExp) ? <b>{part + " "}</b> : part + " "
)}
</div>
);
};
美丽的@rehat101
如果
react-string-replace
不符合您的要求:
杰出的! 我发现它非常有用,因为大多数时候您实际上需要访问原始字符串
我稍微重构了@nullhook的解决方案,使其接受来自查询的变量并模拟 Google 搜索自动完成的行为js
const highlightQueryText = (text: string, filterValue: string) => {
const reg = new RegExp(`(${filterValue})`, 'gi');
const textParts = text.split(reg);
return (
<span style={{ fontWeight: 600 }}>
{textParts.map(part => (part.match(reg) ? <span style={{ fontWeight: 'normal' }}>{part}</span> : part))}
</span>
);
};
所以我发现了一个很好的组合实现 DOMPurify 来清理带有 html-react-parser 的 html 字符串,以在其中找到目标标记并将其转换为 JSX 组件 - 我使用带有传递道具的 Rebass 作为示例......结果非常好,两个包将帮助你避免滚动你自己的解析器的开销,我只是不推荐这个没有清理的解析器包。 对于那些为此苦苦挣扎的人,仍然可以考虑一下这个代码笔的价值: https ://codesandbox.io/s/eager-wiles-5hpff
嘿杰西,
这似乎是一个非常好的组合,用于获取文本并将其转换为
反应组件! 更换零件肯定会很好
带组件的字符串。
感谢分享。
在 JAMstack 站点中将 Markdown 转换为组件也很有用。
最好的祝福,
德里克
Derek R. Austin,PT,DPT,MS,BCTMB,LMT,CSCS
在 LinkedIn 上加入我: https :
2020 年 2 月 26 日,星期三,下午 4:35,Jesse Lewis [email protected]写道:
所以我找到了一个很好的组合来实现 DOMPurify 来清理 html
带有 html-react-parser 的字符串以在其中查找目标标记并进行转换
到 JSX 组件 - 我使用带有传递道具的 Rebass 作为示例..
出来的很好,这两个包将帮助您避免开销
滚动你自己的解析器,我只是不推荐这个解析器包
没有消毒。 对于那些为此苦苦挣扎的人来说,仍然可能有范围
这个代码笔的价值:
https://codesandbox.io/s/eager-wiles-5hpff。 对任何改进的反馈
也非常感谢。—
您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/facebook/react/issues/3386?email_source=notifications&email_token=AMV42QTV4FDXZIFXCGB3NZDRE3OATA5CNFSM4A5VRBI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJLQ9TDN5LMVXHJQ19000000000000000000000785600004
或取消订阅
https://github.com/notifications/unsubscribe-auth/AMV42QXARIOKOYSJ4C5IFQLRE3OATANCNFSM4A5VRBIQ
.
您可以将
split
函数与正则表达式一起使用,然后替换捕获的部分,如下所示:var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi); for (var i = 1; i < parts.length; i += 2) { parts[i] = <span className="match" key={i}>{parts[i]}</span>; } return <div>{parts}</div>;
如果这不清楚,请告诉我。
这很好用。 有什么方法可以让它在 Angular 中工作? 我已经发布了一个关于它的问题,使用您的代码:
https://stackoverflow.com/questions/60889171/wrap-certain-words-with-a-component-in-a-contenteditable-div-in-angular
你好朋友,我需要你的帮助,我正在使用 React Native,我需要做的是从我从数据库中提取的文本中应用格式(字体颜色、链接)来制作@mentions ,如果在text 找到 1 个单一匹配,使得替换一切顺利,但是! 如果文本中有多个@mentions ,则会引发错误。
/////文本示例: _hey发生了什么@-id:1-一切正常??
////列出用户它的数组,例如:[idusuario: "1", usuario: "@luigbren", format: "@-id:1-".....]
const PatternToComponent = (text, usuarios,) => {
let mentionsRegex = new RegExp(/@-(id:[0-9]+)-/, 'gim');
let matches = text.match(mentionsRegex);
if (matches && matches.length) {
matches = matches.map(function (match, idx) {
let usrTofind = matches[idx]
//////////////////////////////////////////////////////////////////
const mentFormat = listusers.filter(function (item) {
const itemData = item.format;
return itemData.indexOf(usrTofind) > -1;
});
if (mentFormat.length > 0) {
let idusuario = mentFormat[0].idusuario
let replc = mentFormat[0].usuario
console.log(usrTofind) //// here find @-id:1-
console.log(replc) //// here is <strong i="12">@luigbren</strong> for replace
////////// now here replace part of the string, @-id:1- with a <Text> component
///////// with <strong i="13">@luigbren</strong> and the link, this is repeated for every <strong i="14">@mention</strong> found
parts = text.split(usrTofind);
for (var i = 1; i < parts.length; i += 2) {
parts[i] = <Text key={i} style={{ color: '#00F' }} onPress={() => { alert('but this is'); }}>{replc}</Text>;
}
return text = parts;
/////////////////////////////////////////////////////////////////////
} else {
return text
}
});
} else {
return text
}
return text
};
以这种方式,只有在文本中只有一个提及时,代码才对我有效,例如 '_hey 发生了什么 @-id:1- 一切正常 ??_' ,但是当放置不止一个提及时,它会给我一个错误,例如:'_hey发生了什么@-id:1-一切正常?? @-id:2- @-id:3-_' ... 错误: TypeError: text.split 不是函数,如果不是放置 _parts = text.split(usrTofind);_ 我放置 _parts = text.toString ().split(usrTofind);_ 它给了我一个 [Object Object] 错误
您可以使用html-react-parser
来解析字符串,然后将节点名称替换为 jsx 组件。 这种类型的替换将允许您通过替换字符串动态地使用 react 元素。
parse(body, {
replace: domNode => {
if (domNode.name === 'select') { // or
return React.createElement(
Select, // your react component
{ },
domToReact(domNode.children)
);
}
}
有人告诉我如何替换字符串中的react-router-dom
?
例子:
var text = "Are You okay <strong i="9">@sara</strong> ?";
var href= <Link to={{
pathname: '/user/sara',
}}> <strong i="10">@sara</strong> </Link>;
var replace = text.replace("@sara", href);
//output : Are You okey [Object Object] ?
我真的不知道 [Object Object] 是谁? 我说“你还好吗@sara”,但这段代码调用了其他人!
我在react-native
有几乎相同的问题,如果有人可以帮助我,我将不胜感激
除了这个包https://www.npmjs.com/package/regexify-string对我没有任何帮助
我正在使用这个功能:
export const replaceWithHtml = (
text: string,
textToReplace: string,
replaceValue: any,
): any[] => {
const delimiter = '|||||'
return text && text.includes(textToReplace)
? text
.replace(textToReplace, `${delimiter}${textToReplace}${delimiter}`)
.split(delimiter)
.map((i) => {
if (i === textToReplace) {
return replaceValue
} else {
return i || null
}
})
: text
}
像那样:
const text = 'This is an [icon]'
replaceWithHtml(
text,
'[icon]',
<i className="icon-cogs" />,
)
我只是想要一个简单的插值工具,用某些元素替换某些关键字。
为了减少输出中的元素数量,我使用了React.Fragment
。
const interpolate = (text, values) => {
const pattern = /([$0-9]+)/g
const matches = text.match(pattern)
const parts = text.split(pattern)
if (!matches) {
return text
}
return parts.map((part, index) => (
<Fragment key={part + index}>{matches.includes(part) ? values[part] : part}</Fragment>
))
}
// ...
<p>
{interpolate('$1 with $2 is fun!', {
$1: <em>Playing</em>,
$2: <strong>JavaScript</strong>,
})}
</p>
// <p><em>Playing</em> with <strong>JavaScript</strong> is fun!</p>
感谢@sophiebits关于split()
想法🙏
基于@pedrodurek的解决方案,这里有一些可以满足我特定需求的内容(使用可读键进行翻译,而不仅仅是数字):
export const insertComponentsIntoText = (
str: string,
replacements: {
[key: string]: React.ReactNode
}
) => {
const splitRegex = new RegExp(/\[\[(\w*)\]\]/g);
const parts = str.split(splitRegex);
return parts.map(part => {
if (replacements.hasOwnProperty(part)) {
return replacements[part];
}
return part;
});
};
例子:
insertComponentsIntoText(`"Please accept our [[privacyPolicyLink]] and [[termsLink].", {
"privacyPolicyLink": <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a>,
"termsLink": <a key="termsLink" href="/terms">Terms and Conditions</a>
})
……变成……
Please accept our <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a> and <a key="termsLink" href="/terms">Terms and Conditions</a>.
(键是必需的,因为它实际上变成了一个数组,而 react 不喜欢没有键的数组元素。)
除了这个包https://www.npmjs.com/package/regexify-string对我没有任何帮助
我也是。 尝试了所有这些,只有这个包有效。 谢谢!
最有用的评论
您可以将
split
函数与正则表达式一起使用,然后替换捕获的部分,如下所示:如果这不清楚,请告诉我。