简体   繁体   English

在 DangerousSetInnerHTML 中从 onclick 调用 React 组件函数

[英]Call React Component Function from onclick in dangerouslySetInnerHTML

React newbie here.在这里反应新手。 I have a contenteditable div which has dangerouslySetInnerHTML as the child, since I need to format whatever the user enters,at runtime.我有一个contenteditable div,它有dangerouslySetInnerHTML作为孩子,因为我需要在运行时格式化用户输入的任何内容。 On a particular span click inside the HTML, I want to setState one of the variables of the containing component.在 HTML 内的特定跨度单击上,我想setState包含组件的变量之一。

Can this be done?这能做到吗?

If not, how should I change my structure ?如果没有,我应该如何改变我的结构?

Here's the code:这是代码:

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

}

the doSomething() method is what I'm taking about. doSomething() 方法是我正在研究的。

If you want your spans to respond to click events, you should assign event handler(doSomething) only after your component is rerendered, because when you assing new value to innerHtml, all event handlers within this component are cleaned.如果你希望你的跨度响应点击事件,你应该只在你的组件重新渲染后分配事件处理程序(doSomething),因为当你为 innerHtml 分配新值时,这个组件中的所有事件处理程序都会被清除。 Another solution is using event delegation like this:另一种解决方案是使用这样的事件委托:

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

Another possible solution is to work with DOM tree directly using createElement, createTextNode and appendChild methods.另一种可能的解决方案是使用 createElement、createTextNode 和 appendChild 方法直接使用 DOM 树。

Try this:尝试这个:

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

I had a similar requirement recently.我最近也有类似的需求。 The react app was being given a block of html with href attributes that needed to be converted into onClick events so that we could resolve and route the links within the react app. react 应用程序被赋予了一个带有 href 属性的 html 块,需要将其转换为 onClick 事件,以便我们可以在 react 应用程序中解析和路由链接。

My solution was to use regex and then register my own event listeners我的解决方案是使用正则表达式,然后注册我自己的事件侦听器

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM