反应-将点击侦听器添加到危险的SetInnerHTML子元素

时间:2018-11-11 07:41:25

标签: reactjs

我有以下html文本:

"<span id='capo' class='capo' data-capo=3>Capo 3</span>"

这是通过dangerouslySetInnerHTML

插入的较大html的一部分。

我有一个这样的听众:

componentDidMount() {
  document.getElementById('capo').addEventListener('click', this.changeKey);
}

但是,这仅适用于一次单击,此后侦听器不存在。我猜是因为React已经替换了组件(因为我更改了this.changeKey中的状态),因此侦听器不再存在。

如何可靠地为React组件设置侦听器?

2 个答案:

答案 0 :(得分:2)

在这种情况下,您可以利用事件冒泡!

只需将事件侦听器添加到上部元素(带有dangerouslySetInnerHTML的元素即可)监听点击并确保e.target.id等于所需的元素ID。

查看下面的示例(它使用dangerouslySetInnerHTML来说明事件冒泡如何工作以及如何在React中使用它,在现实生活中您不应编写这样的组件):

class Element extends React.Component {
  state = {
    loadTime: 0,
    lastUpdate: 0
  };
  
  lastUpdateTimer = null;

  componentDidMount() {
    this.resetTimer();
    
    this.lastUpdateTimer = setInterval(this.setLastUpdate, 1000);
    
    this.dynamicContentElement.addEventListener("click", this.handleClick)
  }
  
  componentWillUnmount() {
    clearInterval(this.lastUpdateTimer);
    this.dynamicContentElement.removeEventListener(this.handleClick)
  }
  
  resetTimer() {
    const now = Date.now();

    this.setState({
      loadTime: now,
      lastUpdate: now
    });
  }
  
  setLastUpdate = () => {
    this.setState({
      lastUpdate: Date.now()
    });
  }

  getDynamicContent() {
    const time = Math.round((this.state.lastUpdate - this.state.loadTime) / 1000);
    return {
      __html: `<p>
        You are here: <strong>${time}</strong> seconods.
        <br>
        <button id="btn">Click to reset counter</button>
       </p>`
    };
  }
  
  handleClick = (e) => {
    if (e.target.id === "btn") {
      this.resetTimer();
    }
  }

  render() {
    return (
      <div>
        Dynamic content below:
        <div
          ref={el => this.dynamicContentElement = el}
          dangerouslySetInnerHTML={this.getDynamicContent()}
        />
      </div>
    );
  }
}


ReactDOM.render(
  <Element />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

答案 1 :(得分:1)

每当状态发生变化时,React都会删除html并将其替换。

此代码仅在首次加载组件时执行,而不在状态更改和html元素(及其侦听器)被擦除时执行:

componentDidMount() {
  document.getElementById('capo').addEventListener('click', this.changeKey);
}

但是此代码将在每次重新渲染组件时运行(因此,每当创建一个新的html元素时,便会附加一个新的侦听器):

componentDidUpdate() {
  document.getElementById('capo').addEventListener('click', this.changeKey);
}