Я использую React Digraph , чтобы создать интерфейс, где пользователь может создавать и редактировать конечные автоматы. Интерфейс несколько удобен (по крайней мере, с точки зрения создания или удаления узлов с помощью сочетаний клавиш), но мне нужно обновить сам интерфейс, чтобы пользователь мог сделать это только с помощью мыши. Для этого я представил следующий интерфейс:
![interface](https://i.stack.imgur.com/47rH6.png)
С точки зрения кода это было довольно легко. Что касается API, мне просто пришлось переопределить метод renderNode
и использовать элемент foreignObject
для вставки HTML в SVG, используемый API:
public renderNode = (nodeRef: any, data: any, id: string, selected: boolean, hovered: boolean) => {
const positioning = data.type === 'required' ? styles.required : styles.optional;
return (
<g className={`shape`}>
{!selected ? null : (
<foreignObject x="-77" y="-77" width="154" height="77" xmlnsXlink="http://www.w3.org/1999/xlink">
<i className={`fas fa-edit ${styles.btn} ${positioning} ${styles.edit}`} />
<i
className={`fas fa-minus-square ${styles.btn} ${positioning} ${styles.delete}`}
onClick={() => {
console.log('onClick');
this.deleteNode(id);
}}
/>
</foreignObject>
)}
<use
className={`node ${hovered ? 'hovered' : ''} ${selected ? 'selected' : ''}`}
x="-77"
y="-77"
width="154"
height="154"
xlinkHref={`#${data.type}`}
>
<svg viewBox="-27 0 154 154" id={data.type} width="154" height="154">
<rect transform="translate(50) rotate(45)" width="109" height="109" />
</svg>
</use>
</g>
);
};
Теперь все должно работать согласно плану, но по какой-то причине событие onClick
не перехватывается. Не отображается console.log, и не вызывается функция deleteNode
.
Я использую:
"react": "^16.6.1",
"react-digraph": "^6.0.0",
Google Chrome Version 72.0.3626.119 (Official Build) (64-bit)
Есть идеи, почему это происходит?
Заранее спасибо.
Редактировать
После предложения Джеймса Делани я попытался добавить ссылки и, впоследствии, прослушиватели событий для всех доступных узлов. Поскольку я потенциально получаю информацию о машине из бэкэнда, я не могу статически создавать все ссылки. Поэтому я попытался создать «список ссылок» на componentDidMount
после получения узлов и вызвать метод addEventListener
на всех найденных узлах, добавив прослушиватели событий в этот список и подключив ссылки, когда узлы будут визуализированы. , На практике это componentDidMount
:
public componentDidMount(): void {
const { machine } = this.props;
this.setState({ graph: machine ? stateMachineToGraph(machine) : initialGraph }, () => {
this.state.graph.nodes.forEach(node => {
const del = `${node.id}delete`,
edit = `${node.id}edit`;
this[del].addEventListener('click', this.deleteNode(node.id));
this[edit].addEventListener('click', this.editNode(node.id));
});
});
}
И это будет foreignObject
, заявленное ранее:
<foreignObject x="-77" y="-77" width="154" height="77" xmlnsXlink="http://www.w3.org/1999/xlink">
<i
ref={edit => (this[`${id}edit`] = edit)}
className={`fas fa-edit ${styles.btn} ${positioning} ${styles.edit}`}
/>
<i
ref={del => (this[`${id}delete`] = del)}
className={`fas fa-minus-square ${styles.btn} ${positioning} ${styles.delete}`}
/>
</foreignObject>
К сожалению, это не работает, и я попытался перебрать это решение, используя списки явно или используя статические ссылки (для целей тестирования). Не было достигнуто никакого прогресса.
Редактировать 2 :
Принимая во внимание возможное решение, описанное выше, я сделал еще несколько итераций и добавил прослушиватели событий только тогда, когда узлы были отрисованы. Таким образом, метод renderNode
стал таким:
public renderNode = (nodeRef: any, data: any, id: string, selected: boolean, hovered: boolean) => {
console.log(id);
if (this[`${id}edit`] && this[`${id}delete`]) {
this[`${id}edit`].addEventListener('click', this.editNode(id));
this[`${id}delete`].addEventListener('click', this.deleteNode(id));
}
const positioning = data.type === 'required' ? styles.required : styles.optional;
...
Пока я не проверяю, присутствуют ли уже прослушиватели событий для определенного узла, я сделаю это позже. Для этой реализации я, наконец, могу удалить узлы, но она не распознает событие click. Я просто зависаю на узле, и событие запускается (вместе с событием 'edit'), и узел удаляется. Почему это происходит?
Спасибо.