从onclick在dangerouslySetInnerHTML中调用React Component Function

时间:2015-05-29 07:35:43

标签: javascript reactjs

在这里反应新手。我有一个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()方法正是我所采取的。

3 个答案:

答案 0 :(得分:5)

如果希望跨度响应单击事件,则只应在重新呈现组件后分配事件处理程序(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树。

答案 1 :(得分:1)

试试这个:

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} />
    );
}

答案 2 :(得分:0)

我最近有类似的要求。为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)
}