从dangouslysetinnerhtml中的onclick调用React组件函数

Call React Component Function from onclick in dangerouslySetInnerHTML

本文关键字:React 组件 函数 调用 onclick dangouslysetinnerhtml 中的      更新时间:2023-09-26

React新手。我有一个contenteditablediv,它有dangerouslySetInnerHTML作为子div,因为我需要在运行时格式化用户输入的任何内容。在一个特定的span内点击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()方法

如果你想让你的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树

试试这个:

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

我最近有一个类似的需求。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)
}