【问题标题】:How to change a x3dom shape with onClick, when using React?使用 React 时如何使用 onClick 更改 x3dom 形状?
【发布时间】:2019-03-02 03:18:16
【问题描述】:

我正在尝试将 React 与 X3DOM 一起使用。 我希望能够单击红色 x3dom <box>,以便在按下时将其颜色更改为蓝色。我尝试在<shape> 标记中使用 onClick 方法。我只能通过按下 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'));

谁能给我一个解决方案,或者解释为什么这不起作用。我将不胜感激。

【问题讨论】:

    标签: html reactjs x3d x3dom


    【解决方案1】:

    正如@Johannes 已经指出的那样,您需要在初始化 X3DOM 之后添加事件侦听器。 如果您仔细查看https://doc.x3dom.org/tutorials/animationInteraction/picking/index.html,您会发现它们明确声明:

    警告:onclick函数的调用由x3dom处理 直接调用回调函数,因为addEventListener 方法需要被覆盖。没有页面范围的 onclick 事件 抛出,因此只有在 之后才能将侦听器附加到该对象。 在这种情况下,不要使用$("#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

    【讨论】:

    • 我在本地主机上的应用程序中尝试了 codepen 中的代码。但这对我不起作用。除了单击框的能力之外的所有内容都按预期工作,即使是在形状标签内显示 onClick 方法的 console.log 消息。有什么理由不应该在本地主机上工作吗?
    • 不,它应该与在 codepen 上的工作方式相同。没有额外的魔法。使用的是file:/// 还是http://?也许在 codepen 上使用的版本和您本地使用的版本之间存在差异?如果您可以显示一些代码,例如作为 GIST,发现错误会更容易。
    【解决方案2】:

    问题是 X3DOM 直接调用 eventHandlers。 引用自docu

    onclick函数的调用由x3dom直接调用回调函数处理,因为addEventListener方法需要被覆盖。不会引发页面范围的 onclick 事件,因此只有在 之后才能将侦听器附加到该对象。

    我尚未对此进行测试,但在 componentDidMount 中添加一次 onclick 可能是可行的方法。

    【讨论】:

      【解决方案3】:

      不确定这是否是最佳解决方案,但我能够通过使用使其工作 componentDidUpdate()。我通过给&lt;shape&gt; 一些id 添加了一个eventListner。我还必须删除 eventListner 以避免无限循环。使用componentDidUpdate() 的问题是组件必须以某种方式更新,然后才能使用该方法。我通过添加一个额外的状态“开始”来做到这一点,我在应用程序运行的第一秒后从 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'));
      

      【讨论】:

        【解决方案4】:

        几周以来我都遇到了同样的问题,感谢您对问题的回答以及这篇不相关的帖子:Why does an onclick property set with setAttribute fail to work in IE?,我能够使其与onClickmouseover 事件一起使用。

        如上述答案之一所述,X3Dom 带有自己的一组附加到 onClick 事件的函数。正如 X3DOM 文档中提到的,您只能在文档加载后附加您的事件。 @mistapink 的想法也是正确的,除了 setAttributemethod 由于某些原因不起作用。所以我做到了:

        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 (...)
        };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-12-10
          • 1970-01-01
          • 2012-01-03
          • 2019-08-09
          • 2012-06-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多