Как изменить форму x3dom с помощью onClick при использовании React? - PullRequest
0 голосов
/ 26 сентября 2018

Я пытаюсь использовать React вместе с X3DOM.Я хочу иметь возможность нажимать на красный x3dom <box>, чтобы при нажатии он менял цвет на синий.Я пытался использовать метод onClick в теге <shape>.Я смог сделать это только нажатием html <button>.У меня также есть кнопка в коде.

Это мой файл index.js.

import React from "react";
import ReactDOM from "react-dom";

class Toggle extends React.Component {
    constructor(props) {
        super(props);
        this.state = { isToggleOn: true };

        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        this.setState(prevState => ({
            isToggleOn: !prevState.isToggleOn
        }));
    }

    render() {
        return (
        <div>
            <x3d width='500px' height='300px' >
                <scene>
                    <shape onClick={this.handleClick}>
                        <appearance>
                            <material id='color' diffusecolor={this.state.isToggleOn ? '1 0 0' : '0 0 1'}> </material>
                        </appearance>
                        <box></box>
                    </shape>
                </scene>
            </x3d>

            <button onClick={this.handleClick}>
                {this.state.isToggleOn ? 'BLUE' : 'RED'}
            </button>

        </div>
        );
    }

}

ReactDOM.render(<Toggle />, document.getElementById('toggle'));

Может кто-нибудь дать мне решение или объяснить, почему это не работает.Буду очень признателен за любой ответ.

Ответы [ 4 ]

0 голосов
/ 02 мая 2019

У меня была такая же проблема в течение нескольких недель, благодаря ответам на ваш вопрос и этому посту, не связанному с этой темой: Почему свойство onclick, установленное с помощью setAttribute, не работает в IE? , я былвозможность заставить его работать с onClick и mouseover событиями.

Как сказано в одном из приведенных выше ответов, X3Dom поставляется со своим собственным набором функций, связанных с событием onClick.И, как упоминалось в документации X3DOM, вы можете прикрепить свое событие только после загрузки документа.Также идея @mistapink была правильной, за исключением того, что метод setAttribute не работает по некоторым причинам.Итак, я сделал это:

const Scene = () => {
   const [toggle, setToggle] = useState(false);
   const handleMouseOver = () => {/* do some mouse over stuff here */};
const handleClick = () => setToggle(prevToggle => !prevToggle};
   useEffect(() => {
      const 3dObject = document.getElementById('my-3d-object'); 
/* I guess you can also try to use a reference, don't know if it'll work */
      document.onload = () => {
         3dObject.addEventListener("mouseover", handleMouseOver);
/* magic happens here  */
         3dObject.onclick = () => handleClick(
/* you can pass some extra arguments here */
);
      }
      return () => sphere.removeEvenetListener("mouseover", handleMouseOver);
    });

  return (...)
};
0 голосов
/ 01 октября 2018

Как уже заметил @Johannes, вам нужно добавить прослушиватели событий после инициализации X3DOM.Если вы внимательно посмотрите на https://doc.x3dom.org/tutorials/animationInteraction/picking/index.html, то обнаружите, что они явно заявляют:

Предупреждение : вызов функции onclick обрабатывается x3dom путем непосредственного вызовафункция обратного вызова, поскольку метод addEventListener необходимо было перезаписать.Никаких событий щелчка по всей странице не генерируется, поэтому присоединение слушателя к этому объекту возможно только после .В этом случае не используйте $("#myBox").on("click", doSomething(event)), а $("#myBox").attr("onclick", "doSomething(event)").Либо подождите, пока страница не загрузится полностью и не сработает событие document.onload.

Рабочий пример может выглядеть следующим образом:

var glob = {};
class Toggle {
    ...    
    componentDidMount() {
      glob.handleClick = this.handleClick;
      var k = document.getElementsByTagName('shape')[0];
      k.setAttribute('onclick', 'glob.handleClick()');
    }

Обратите внимание, что мне пришлосьпредставить глобальный объект, чтобы заставить его работать, что, вероятно, является просто недостатком моих знаний о React.Вы можете найти лучший способ.

Вы также можете увидеть его по адресу: https://codepen.io/pgab/pen/gBpEWo

0 голосов
/ 02 октября 2018

Не уверен, что это лучшее решение, но я смог заставить его работать, используя componentDidUpdate().Я добавил eventListner, дав <code><shape> некоторый идентификатор.Мне также пришлось удалить eventListner, чтобы избежать бесконечного цикла.Проблема с использованием componentDidUpdate() заключается в том, что компонент должен как-то обновляться, прежде чем метод можно будет использовать.Я сделал это, добавив дополнительное состояние 'start', которое я обновляю с false до true после первой секунды при запуске приложения.

import React from "react";
import ReactDOM from "react-dom";

class Toggle extends React.Component {
 constructor() {
    super();
    this.state = { isToggleOn: true, start: false};

    this.handleClick = this.handleClick.bind(this); 
 }

 handleClick() {
    this.setState(prevState => ({
        isToggleOn: !prevState.isToggleOn
    }));
    console.log("Pressed");
 }

 componentDidUpdate() {
    console.log('Component update');

    //Have to do this to avoid potential infinty loop
    document.getElementById('someId').removeEventListener("click", this.handleClick);

    document.getElementById('someId').addEventListener("click", this.handleClick);
 }

 render() {

    //Need to update component once, to run componentDidUpdate
    if(!(this.state.start)){
        setTimeout(() => {
            this.setState({start: true });
        }, 1000)
    }
    //

    return (
        <div>
        <x3d width='500px' height='300px'>
            <scene>
                <shape id="someId">
                    <appearance>
                        <material id='color' diffusecolor={this.state.isToggleOn ? '1 0 0' : '0 0 1'}> </material>
                    </appearance>
                    <box></box>
                </shape>
            </scene>
        </x3d>
    </div>
    );  
  }
 }

ReactDOM.render(<Toggle />, document.getElementById('toggle'));
0 голосов
/ 27 сентября 2018

Проблема в том, что X3DOM напрямую вызывает eventHandlers.Цитата из document :

Вызов функции onclick обрабатывается x3dom путем прямого вызова функции обратного вызова, поскольку метод addEventListener необходимо перезаписать.Никаких событий onclick на всю страницу не генерируется, поэтому присоединение слушателя к этому объекту возможно только после .

Я не проверял это, но добавлял onclick один раз в componentDidMountможет быть, путь.

...