【问题标题】:How to compare two textfield contents and highlight the characters that are changed in ReactJS?如何比较两个文本字段内容并突出显示 ReactJS 中更改的字符?
【发布时间】:2021-07-05 18:58:26
【问题描述】:

我需要比较两个 material-ui 文本字段的内容并突出显示两者中更改的字符。这基本上与此处提出的问题相同,但针对的是 ReactJS 而不是 C# Windows 窗体:

How to compare two rich text box contents and highlight the characters that are changed?

【问题讨论】:

标签: javascript reactjs material-ui compare


【解决方案1】:

非常感谢回复的人。我有趣地找到了一个解决方案。希望这可以帮助其他人解决这个问题。

这个概念是我有两个带有内容的可编辑文本框,我强调了两者之间的区别。首先,让我们解决突出显示的问题。这很简单。我使用了 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,则忽略该项目。例如,如果string1catstring2bat,则output 将是cat,但c 以黄色突出显示。

那么如何将这个突出显示的文本插入到 Material-Ui 文本框中?好吧,我选择了使用 contentEditable 控件的路线。您可以将 p 标记(和其他标记)转换为呈现 HTML 的可编辑文本框。这不是我喜欢的解决方案,因为它带来了处理 XSS 的麻烦,但这似乎是不可避免的。如果有人遵循此解决方案,我恳请您实施客户端和服务器端输入清理以防止 XSS。后者尤其重要,因为可以通过各种方法轻松绕过客户端验证,例如使用检查元素修改页面或使用数据包制作工具。

以下是 HTML 中 contentEditable 文本框的外观:

<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

【讨论】:

    【解决方案2】:

    如果您可以提供一些代码,那么您的代码当前是如何设置的以及如何实现该功能会更容易理解。我试图按照您提到的内容创建一些东西(沙盒: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);
    
    

    现在,我们遇到了将它们渲染到屏幕上并突出显示它们的问题。一种方法(它很丑,但确实如此)是:

    1. 跟踪不同字符的索引并将它们设置为状态
    2. 将字符串转成数组
    3. 通过数组映射,如果当前索引在 state 中找到(意味着它是“更改”值),则返回一个 css 修改的 span 以“突出显示”它

    我将其设置为在单击按钮时显示,您可以在此处查看: 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>
      );
    };
    
    

    【讨论】:

      猜你喜欢
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      • 2019-02-19
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      相关资源
      最近更新 更多