#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>
);
};
вы можете увидеть полный код в этой изолированной среде