Html 使用React时,如何使用onClick更改x3dom形状?

Html 使用React时,如何使用onClick更改x3dom形状?,html,reactjs,x3d,x3dom,Html,Reactjs,X3d,X3dom,我正在尝试将React与X3DOM一起使用。 我希望能够单击红色的x3dom,以便在按下时将其颜色更改为蓝色。我尝试在标记中使用onClick方法。我只能通过按html来实现这一点。我在代码中也有按钮 这是我的index.js文件 import React from "react"; import ReactDOM from "react-dom"; class Toggle extends React.Component { constructor(props) {

我正在尝试将React与X3DOM一起使用。 我希望能够单击红色的x3dom
,以便在按下时将其颜色更改为蓝色。我尝试在
标记中使用onClick方法。我只能通过按html
来实现这一点。我在代码中也有按钮

这是我的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'));
从“React”导入React;
从“react dom”导入react dom;
类切换扩展了React.Component{
建造师(道具){
超级(道具);
this.state={istogleon:true};
this.handleClick=this.handleClick.bind(this);
}
handleClick(){
this.setState(prevState=>({
isToggleOn:!prevState.isToggleOn
}));
}
render(){
返回(
{this.state.isToggleOn?'BLUE':'RED'}
);
}
}
ReactDOM.render(,document.getElementById('toggle');

有人能给我一个解决方案,或者解释一下为什么这不起作用。我非常感谢您的回答。

问题是X3DOM直接调用EventHandler。 引自:

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


我还没有对此进行测试,但是在
组件中添加onclick once didmount
可能是一个不错的选择。

正如@Johannes已经指出的,您需要在X3DOM初始化后添加事件侦听器。 如果你仔细观察,你会发现他们明确指出:

警告:onclick函数的调用由x3dom通过 直接调用回调函数,因为addEventListener 方法需要被覆盖。不支持页面范围的onclick事件 抛出,因此只有在之后才能将侦听器附加到此对象。 在这种情况下,不要使用
$(“#myBox”)。在(“单击”,doSomething(事件))
但是,
$(“#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缺乏了解。你可能会找到更好的办法


您还可以在以下位置看到它:

不确定这是否是最好的解决方案,但我可以使用
componentdiddupdate()
。我通过给
一些id添加了一个eventListner。我还必须删除eventListner以避免无限循环。使用
componentdiddupdate()
的问题是,组件必须以某种方式更新,然后才能使用该方法。为此,我添加了一个额外的状态“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'));
从“React”导入React;
从“react dom”导入react dom;
类切换扩展了React.Component{
构造函数(){
超级();
this.state={istogleon:true,start:false};
this.handleClick=this.handleClick.bind(this);
}
handleClick(){
this.setState(prevState=>({
isToggleOn:!prevState.isToggleOn
}));
控制台日志(“按下”);
}
componentDidUpdate(){
console.log(“组件更新”);
//必须这样做以避免潜在的infinty循环
document.getElementById('someId')。removeEventListener(“单击”,this.handleClick);
document.getElementById('someId').addEventListener(“单击”,this.handleClick);
}
render(){
//需要更新组件一次,才能运行componentDidUpdate
if(!(this.state.start)){
设置超时(()=>{
this.setState({start:true});
}, 1000)
}
//
返回(
);  
}
}
ReactDOM.render(,document.getElementById('toggle');

多亏了你问题的答案,以及这篇无关的帖子,我几个星期来都遇到了同样的问题:,我能够用
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 (...)
};

我在本地主机上的应用程序中尝试了codepen中的代码。但这对我不起作用。除了单击框的功能外,所有功能都按预期工作,即使是在shape标记中显示onClick方法的console.log消息也是如此。有什么理由不应该在localhost上工作吗?没有,它应该与codepen上的工作方式相同。没有额外的魔力。正在使用
文件://
http://
?在codepen上使用的版本和您的本地版本之间可能存在差异?如果您可以显示一些代码,例如作为要点,则更容易发现错误。