如何解决如何比较两个文本字段内容并突出显示在 ReactJS 中更改的字符?
我需要比较两个 material-ui 文本字段内容并突出显示两者中更改的字符。这基本上与此处提出的问题相同,但对于 ReactJS 而不是 C# Windows 窗体:
How to compare two rich text box contents and highlight the characters that are changed?
解决方法
非常感谢回复的人。我很有趣地想到了一个解决方案。希望这可以帮助其他人解决这个问题。
概念是我有两个带有内容的可编辑文本框,我强调了两者之间的差异。首先,让我们解决突出显示的问题。这很简单。我使用 Squiggs 的方法通过使用以下包来比较两个字符串:
https://github.com/kpdecker/jsdiff
利用 Diff
包,我创建了一个函数来比较两个字符串并返回结果:
function compareStrings(string1,string2) {
let results = Diff.diffChars(string1,string2);
let output = "";
results.forEach((item) => {
if (item.removed) {
output += `<span style="background-color:yellow">${item.value}</span>`;
} else if (!item.added) {
output += `${item.value}`;
}
});
return output;
}
在使用 Diff
包时,它将识别出的差异和相似之处分为不同的项目。它使处理结果变得相对容易。在上面的代码中,迭代 results
中的结果。如果某个项目的 removed
设置为 true,则它是 string1
中不在 string2
中的项目。如果 added
设置为 true,则它是 string2
中不在 string1
中的项目。如果两者都未设置为 true,则它是两个字符串中的一个项目。我的函数的输出将包含 string1
的所有字符。如果某个项目的 added
设置为 true,则该项目将被忽略。例如,如果 string1
为 cat
且 string2
为 bat
,则 output
将为 cat
,但 c
以黄色突出显示.
那么如何将这个突出显示的文本插入到 Material-Ui 文本框中?好吧,我选择沿着使用 contentEditable 控件的路线走下去。您可以将 p
标记(和其他标记)转换为呈现 HTML 的可编辑文本框。这不是我喜欢的解决方案,因为它打开了处理 XSS 的麻烦,但似乎不可避免。如果有人遵循此解决方案,我恳请您实施客户端和服务器端输入卫生以防止 XSS。后者尤为重要,因为可以通过各种方法轻松绕过客户端验证,例如使用检查元素修改页面或利用数据包制作工具。
以下是 contentEditable 文本框在 HTML 中的样子:
<p
id="textbox1"
className="textbox"
variant="outlined"
contentEditable={true}
/>
从这里,我可以将 compareStrings
的结果分配给它:
document.getElementById("textbox1").innerHTML = htmlData
所以最终结果将有两个 contentEditable 文本框。我必须调用 compareStrings 两次并将结果应用于两者。
当然,我只是详细介绍了解决这个问题的要点。还有其他生活质量功能,例如复制和粘贴,详情如下:
Highlight value of @material-ui/core TextField in React at specific indices
,如果您能提供一些代码,那么了解您的代码当前是如何设置的以及如何实现该功能会更容易。我尝试按照您提到的内容创建一些内容(沙箱:https://codesandbox.io/s/sam-cards-forked-jyrlv?file=/src/App.js:0-1786)
说明:
首先,我们需要区分一种方法来找出两个字符串之间的差异。这很简单,可以通过对每个字符串逐个字符进行迭代并将两者进行比较来完成。
const findDiff = (string1,string2) => {
// we will use this to keep an eye on the two strings
let index = 0
while (index < string1.length || index < string2.length) {
const left_char = string1[index]
const right_char = string2[index]
if (left_char !== right_char) {
// they are different
} else {
// they are the same character
}
index++
}
return // return something here
}
findDiff(string1,string2);
现在,我们的问题是将它们渲染到屏幕上并突出显示它们。一种方法(它很丑但确实做到了)是:
- 跟踪不同字符的索引并将它们设置为状态
- 将字符串转换为数组
- 映射数组,如果在 state 中找到当前索引(意味着它是“已更改”的值),则返回一个 css 修改的跨度以“突出显示”它
我将其设置为在单击按钮时显示,您可以在这里看到: https://codesandbox.io/s/sam-cards-forked-jyrlv?file=/src/App.js:0-1786
import "./styles.css";
import { useState,useEffect } from "react";
const string1 = "abcdefg";
const string2 = "adcelig123";
const strar1 = string1.split("");
const strar2 = string2.split("");
export const YourComponent = () => {
const [isHighlightActive,setIsHighlightActive] = useState(false);
const [wrongCharIndexes] = useState(new Set());
// re-calculate the differences between strings whenever they change
useEffect(() => {
findDiff(string1,string2);
},[string1,string2]);
const findDiff = (string1,string2) => {
// we will use this to keep an eye on the two strings
let index = 0;
while (index < string1.length || index < string2.length) {
const left_char = string1[index];
const right_char = string2[index];
if (left_char === right_char) {
wrongCharIndexes.add(index);
}
index++;
}
return;
};
return (
<div className="App">
{isHighlightActive ? (
// map through the two strings and render the highlighted character or regular character
<>
<p className="flex">
{strar1.map((char,index) => {
return wrongCharIndexes.has(index) ? (
<span className="highlighted">{char}</span>
) : (
<>{char}</>
);
})}
</p>
<p className="flex">
{strar2.map((char,index) => {
return wrongCharIndexes.has(index) ? (
<span className="highlighted">{char}</span>
) : (
<>{char}</>
);
})}
</p>
</>
) : (
<div>
<p>{string1}</p>
<p>{string2}</p>
</div>
)}
<button onClick={() => setIsHighlightActive((prev) => !prev)}>
Click me
</button>
</div>
);
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。