Переключение выделения диапазона различий таблицы ReactJS

#javascript #reactjs #diff

#javascript #reactjs #разница

Вопрос:

Я пытаюсь создать приложение ReactJS, которое будет отображать таблицу — я хочу иметь переключатель для отображения / выделения различий — в строках таблицы. Я попытался добавить ссылки в строки таблицы, чтобы попытаться использовать их в качестве входных данных.

текущая изолированная среда https://codesandbox.io/s/hopeful-haibt-q489l?file=/src/Home.js

Некоторая демонстрация с JavaScript http://jsfiddle.net/8c4nt2e1/1 /

введите описание изображения здесь

     import React, { Component } from "react";
    import { withRouter } from "react-router-dom";
    import { connect } from "react-redux";
    import { bindActionCreators } from "redux";
    
    import { Diff } from "diff";
    
    import ReactDOM from "react-dom";
    
    class Home extends Component {
      componentDidMount() {
        console.log("show differences");
      }
    
      onShowDiff() {
        var name = ReactDOM.findDOMNode(this.refs.row1_0); //.value;
        console.log("name", name);
    
        /*
        const diff = Diff.diffChars(
            document.getElementById('row1_0').value, 
            document.getElementById('row1_1').value,
            document.getElementById('row1_2').value,
            document.getElementById('row1_3').value
        );*/
    
        //
    
        /*
        const diff = Diff.diffChars(document.getElementById('input-1').value, document.getElementById('input-2').value);
        const output = diff.reduce((result, change) => {
          if (change.added) return result   '<span data-diff="added">'   change.value   '</span>';
          if (change.removed) return result   '<span data-diff="removed">'   change.value   '</span>'
          return result   change.value;
        }, '');
        */
        //document.getElementById('output').innerHTML = output;
        //console.log(output);
      }
    
      onHideDiff() {
        //const output = document.getElementById('output').innerHTML;
        //document.getElementById('output').innerHTML = output.replace(/<span data-diff=["'](?:added|removed)["']>(. )</span>/gi, '$1');
      }
    
      render() {
        return (
          <div className="Page">
            <button id="show-diff" onClick={this.onShowDiff()}>
              Show diff
            </button>
            <button id="hide-diff" onClick={this.onHideDiff()}>
              Hide diff
            </button>
    
            <div className="table-spec">
              <table>
                <tr>
                  <th>spec1</th>
                  <th>spec2</th>
                  <th>spec3</th>
                  <th>spec4</th>
                </tr>
                <tr>
                  <td ref="row1_0">480GB Adata SU630 SATA SSD</td>
                  <td ref="row1_1">512GB Adata XPG SX8200 Pro NVMe SSD</td>
                  <td ref="row1_2">512GB Adata XPG SX8200 Pro NVMe SSD</td>
                  <td ref="row1_3">2TB NVMe SSD</td>
                </tr>
                <tr>
                  <td ref="row2_0">GeForce RTX 3080 10GB</td>
                  <td ref="row2_1">GeForce GTX 1660 SUPER 6GB</td>
                  <td ref="row2_2">Radeon RX 5500 XT 8GB</td>
                  <td ref="row2_3">GeForce RTX 3090 24GB</td>
                </tr>
                <tr>
                  <td ref="row3_0">Intel Core i5 9400F 2.9GHz</td>
                  <td ref="row3_1">AMD Athlon 3000G 3.5GHz</td>
                  <td ref="row3_2">AMD Ryzen 7 3700X 3.6GHz</td>
                  <td ref="row3_3">Intel Core i9 10900K 3.7GHz</td>
                </tr>
              </table>
            </div>
          </div>
        );
      }
    }
    
    function mapStateToProps(state) {
      return {};
    }
    
    function mapDispatchToProps(dispatch) {
      return bindActionCreators({}, dispatch);
    }
    
    export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Home));
  

идея исходит отсюда
https://www.gsmarena.com/compare.php3?idPhone1=9847amp;idPhone2=9536amp;idPhone3=9256#diff -*,*,
*

Комментарии:

1. Суть вашего вопроса интересна. Но я думаю, вам было бы намного проще организовать это, если бы вы сгенерировали ячейки таблицы из массива данных, используя .map , и используя diff функцию непосредственно в массиве данных, вместо того, чтобы загрязнять код react кучей refs getElementById операторов and . Вот пример

2. Можно ли предположить, что в каждой ячейке таблицы не будет другого HTML?

Ответ №1:

Основные идеи здесь состоят в том, чтобы использовать state для управления тем, как структурирован HTML (согласно (как я думаю) стандартному React) и иметь компонент для каждой строки, чтобы каждая строка могла определять различия и элементы, которые должна иметь каждая строка.

‘DiffRow’ может быть результатом сопоставления с некоторым набором данных строки.

Я не изучал, как использовать Diff для достижения именно того, чего вы хотите, это просто пример использования Diff, который вы дали, и они определяют разницу для каждой ячейки после первой, до первой и добавляют промежутки с классами для вещей, о которых упоминал Diff.

По какой-то причине импорт Diff, похоже, не сработал, поэтому я потребовал его вместо этого.

https://codesandbox.io/s/compassionate-yalow-th57n?file=/src/Home.js

 import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";

const Diff = require("diff");

const diff_part_class_name = (part) =>
  part.added ? "added" : part.removed ? "removed" : "default";

const diff_cells = (cells) => {
  const [first_cell, ...other_cells] = cells;

  return [first_cell].concat(
    other_cells
      .map((content) => Diff.diffChars(first_cell, content))
      .map((diffed) => (
        <>
          {diffed.map((part, index) => (
            <span key={index} className={diff_part_class_name(part)}>
              {part.value}
            </span>
          ))}
        </>
      ))
  );
};

const DiffRow = ({ data, show_diff }) => {
  const cell_data = show_diff ? diff_cells(data) : data;
  return (
    <tr>
      {cell_data.map((content, index) => (
        <td key={index}>{content}</td>
      ))}
    </tr>
  );
};

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = { show_diff: false };
  }

  componentDidMount() {
    console.log("show differences");
  }

  onShowDiff() {
    this.setState({ show_diff: true });
  }

  onHideDiff() {
    this.setState({ show_diff: false });
  }

  render() {
    return (
      <div className="Page">
        <button id="show-diff" onClick={this.onShowDiff.bind(this)}>
          Show diff
        </button>
        <button id="hide-diff" onClick={this.onHideDiff.bind(this)}>
          Hide diff
        </button>

        <div className="table-spec">
          <table>
            <thead>
              <tr>
                <th>spec1</th>
                <th>spec2</th>
                <th>spec3</th>
                <th>spec4</th>
              </tr>
            </thead>
            <tbody>
              <DiffRow
                show_diff={this.state.show_diff}
                data={[
                  "480GB Adata SU630 SATA SSD",
                  "512GB Adata XPG SX8200 Pro NVMe SSD",
                  "512GB Adata XPG SX8200 Pro NVMe SSD",
                  "2TB NVMe SSD"
                ]}
              />
              <DiffRow
                show_diff={this.state.show_diff}
                data={[
                  "GeForce RTX 3080 10GB",
                  "GeForce GTX 1660 SUPER 6GB",
                  "Radeon RX 5500 XT 8GB",
                  "GeForce RTX 3090 24GB"
                ]}
              />
              <DiffRow
                show_diff={this.state.show_diff}
                data={[
                  "Intel Core i5 9400F 2.9GHz",
                  "AMD Athlon 3000G 3.5GHz",
                  "AMD Ryzen 7 3700X 3.6GHz",
                  "Intel Core i9 10900K 3.7GHz"
                ]}
              />
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {};
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({}, dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Home));
  

Комментарии:

1. это выглядит неправильно — оно должно просто выделять различия — например, теги wrap span, где числа / части конкретно отличаются

2. Я обновил таблицу стилей, чтобы скрыть удаленные элементы и выделить добавленные элементы, но я не уверен, что это то, что вы хотели бы, так как тогда вы не получите информацию о том, что находится в первом, но не о том, с чем вы сравниваете. Я бы подумал, что вы могли бы сделать это между двумя строками, выполнив ту же разницу в противоположном направлении, а затем показав добавленное в обеих двух строках; но не уверен, как вы могли бы это сделать при сравнении более двух.

3. Что, если он отсканировал строки — и обнаружил более общее различие — например, если что-то выглядит одинаково в 2 из 3 строк?

4. идея исходит отсюда — gsmarena.com /… , ,*

Ответ №2:

Я думаю, вам не следует использовать библиотеку diff js в этом сценарии.

Я видел пример сравнения сайта, который вы упомянули. проще сравнивать элементы с определенным шаблоном

а не посимвольно.

в gsmaena в столбце есть несколько спецификаций, разделенных запятой.

если у вас тоже есть несколько спецификаций, вы можете сделать так:

 const getWords = (item, array, show_diff) => {
  const seperatedWords = useRef(item.split(","));
  return seperatedWords.current.map((word, i) => (
    <span
      style={
        show_diff amp;amp; !array[0].split(",").includes(word) ? { opacity: 0.3 } : {}
      }
    >
      {word}
      {i !== seperatedWords.current.length - 1 amp;amp; ","}
    </span>
  ));
};

const Row = ({ data, show_diff }) => {
  return (
    <tr>
      {data.map((content, index) => (
        <td key={index}>{getWords(content, data, show_diff)}</td>
      ))}
    </tr>
  );
};
  

если нет, то это тоже проще. вы можете написать:

 const Row = ({ data, show_diff }) => {
  const hasDifference = useRef(!data.every((val, i, arr) => val === arr[0]));
  return (
    <tr>
      {data.map((content, index) => (
        <td
          style={show_diff amp;amp; hasDifference.current ? { opacity: .3 } : {}}
          key={index}
        >
          {content}
        </td>
      ))}
    </tr>
  );
};
  

вы можете увидеть полный код в этой изолированной среде