【问题标题】:Call React Component Function from onclick in dangerouslySetInnerHTML从危险的SetInnerHTML中的onclick调用React组件函数
【发布时间】:2015-05-29 07:35:42
【问题描述】:

在这里反应新手。我有一个contenteditable div,其中有dangerouslySetInnerHTML 作为孩子,因为我需要在运行时格式化用户输入的任何内容。在 HTML 内的特定范围内单击,我想setState 包含组件的变量之一。

这可以吗?

如果没有,我应该如何改变我的结构?

代码如下:

updateText:function(){

    var txt = $('#text_Box').text();

    if(txt.indexOf('@Name') > -1)
    {
        txt = txt.replace('@Name','<span class=\'tagged\' contenteditable = \'false\' onclick=\'doSomething()\'>:Name</span>');

    }
    this.setState({userText:txt});
}, 
render:function(){
  return <div className="inputDiv" contentEditable="true" type="text" className="form-control" id="text_Box" dangerouslySetInnerHTML={{__html:this.state.userText}} onInput = {this.updateText} />

}

doSomething() 方法是我正在研究的。

【问题讨论】:

  • 请向我们展示您目前拥有的代码
  • @marcel,已添加代码。
  • onInput 应该怎么做?它有效吗?它是否按预期调用该方法?
  • onInput 在用户在 div 中输入文本时调用指定的函数。它工作正常。
  • 好的。我不知道这个属性。 :-)

标签: javascript reactjs


【解决方案1】:

如果您希望 span 响应单击事件,则应仅在重新渲染组件后分配事件处理程序(doSomething),因为当您为 innerHtml 分配新值时,此组件中的所有事件处理程序都会被清除。另一种解决方案是使用这样的事件委托:

onClick: function(e) {
    var $el = $(e.target);
    if ($el.is('span.tagged')) {
        this.doSomething($el);
    }
},

render:function(){
    return (
        <div 
            className="inputDiv form-control" 
            contentEditable="true"
            onClick={this.onClick}
            type="text" 
            id="text_Box" 
            dangerouslySetInnerHTML={{__html: this.state.userText}} 
            onInput={this.updateText} />
    );
}

另一种可能的解决方案是直接使用 createElement、createTextNode 和 appendChild 方法处理 DOM 树。

【讨论】:

  • 将要显示的危险 HTML 是动态的,并且可能会根据用户之前选择的选项而改变。在这种情况下,其中可能根本没有任何 ,但是单击任何存在的 DOM 都会调用相同的函数
  • 是的,如果没有 span 元素,div 上会有事件处理程序,但我不明白 marcel 的答案如何帮助解决问题,因为它只是在 updateText 中调用 this.doSomething 方法方法,span 的 onclick 字段接收 doSomething 调用的结果。无论如何,您无法通过这种方式直接访问 this.doSomething 的跨度点击处理程序
  • 我明白你的意思。也许我需要重做这整件事。感谢您指出这一点!
  • @beshanoe - 你的答案是正确的。正如您在接受的解决方案中正确指出的那样(我不明白为什么它被接受而不是您的) this.doSomething 将立即执行,其结果将与字符串的其余部分连接。该方法无法让您安装要在 onClick 中调用的处理程序...
【解决方案2】:

试试这个:

updateText: function() {
    var txt = $('#text_Box').text();

    if (txt.indexOf('@Name') > -1) {
        txt = txt.replace('@Name', '<span class="tagged" contenteditable="false" onclick="' + this.doSomething() + '">:Name</span>');
    }
    this.setState({userText: txt});
}, 

render:function(){
    return (
        <div 
            className="inputDiv form-control" 
            contentEditable="true" 
            type="text" 
            id="text_Box" 
            dangerouslySetInnerHTML={{__html: this.state.userText}} 
            onInput={this.updateText} />
    );
}

【讨论】:

    【解决方案3】:

    我最近有类似的要求。 react 应用程序被赋予了一个带有 href 属性的 html 块,需要将其转换为 onClick 事件,以便我们可以在 react 应用程序中解析和路由链接。

    我的解决方案是使用正则表达式,然后注册我自己的事件监听器

    //given a block of html as a string
    myHtml = '<div href="/goSomewhere"></div>'
    
    //match all href attributes
    let reg: RegExp = /href=".*?"/g
    
    //replace the href attribute with a custom "resolve" attribute
    myHtml.replace(reg, (href: string) => {
      //then match any characters between the quotation marks in the href attribute to extract the uri itself
      let uri = href.match(/(?<=href=").*?(?=")/g)
      return `resolve="${uri}"`
    })
    
    
    //Render the html
    render() { 
       return <div dangerouslySetInnerHTML = {{__html: myHtml}} />
    }
    
    //helper function to return an array containing all nodes with a "resolve" attribute
    getElementByAttribute(attr: string) {
      let nodeList = document.getElementsByTagName('*')
      let nodeArray = []
      for (let i = 0; i < nodeList.length; i++) {
        if (nodeList[i].getAttribute(attr)) nodeArray.push(nodeList[i])
      }
      return nodeArray
    }
    
    //once rendered find the tag that require resolving 
    componentDidUpdate() {
      let nodes = this.getElementByAttribute('resolve')
      for (let i = 0; i < nodes.length; i++) {
        //create pointer outside of the onclick event allowing closure
        let href = nodes[i].getAttribute('resolve')
    
        nodes[i].addEventListener('click', (e) => {
          if (href) this.linkResolver(href);
        })
    
        //remove the custom attribute to cleanup
        nodes[i].removeAttribute('resolve')
      }
    }
    
    //linkResolver is a function within react
    //you now have an onclick event triggered from dangerouslySetInnerHTML
    linkResolver(href: string) {
      console.log(href)
    }

    【讨论】:

      猜你喜欢
      • 2018-04-30
      • 1970-01-01
      • 2021-12-11
      • 2019-04-26
      • 2022-01-23
      • 2019-06-18
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      相关资源
      最近更新 更多