Javascript 如何将onclick事件添加到reactjs中由危险的lySetinerHTML呈现的字符串中?

Javascript 如何将onclick事件添加到reactjs中由危险的lySetinerHTML呈现的字符串中?,javascript,html,reactjs,onclick,innerhtml,Javascript,Html,Reactjs,Onclick,Innerhtml,我有一根绳子,也就是 let string= "Hello <b>Click here</b>"; render() { return (<div dangerouslySetInnerHTML={this.createMarkup(value)}/> } createMarkup = value => { return { __html: value }; }; let string=“Hello单击此处”; render()

我有一根绳子,也就是

let string= "Hello <b>Click here</b>";

render() {
return (<div dangerouslySetInnerHTML={this.createMarkup(value)}/>
}

createMarkup = value => { 
        return { __html: value };
 };
let string=“Hello单击此处”;
render(){
返回(
}
createMarkup=value=>{
返回{uuuhtml:value};
};
我想要的是能够将onclick事件添加到
标记,并在单击时执行状态操作

根本的问题是,我有一个函数,它应该呈现API传递的任何内容。API将发送一个字符串“Money received for order ID 123”,或者可以是我无法控制的任何字符串。后来,我得到一个要求,即粗体的项必须是可单击的,以便执行一些操作。我没有没有其他解决办法

如何实现这一点?

警告:这听起来像是一个问题,根本问题(不管是什么)应该以不同的方式解决,这样您就不必向通过
危险的LysetinerHTML创建的DOM元素添加单击处理程序(理想情况下,您根本不必通过
危险的SetinenerHTML
创建DOM元素)。但是回答您提出的问题:(您已经澄清了用例;下面的解决方案1适用,并且不是不好的做法。)

我认为你不能直接这么做。我可以想到两种解决方案:

  • div
    上使用委托事件处理程序:在
    div
    上添加一个click处理程序,但仅当click通过
    b
    元素时才采取操作

  • div
    上使用
    ref
    ,然后在
    componentDidMount
    componentdiddupdate
    中连接单击处理程序(通过
    querySelector
    或类似工具查找
    div
    中的
    b
    元素),大致如下:

  • 下面是#1的一个例子:

    …或者,如果您需要支持没有
    ParentNode#closest
    的旧浏览器:

    clickHandler(e) {
        // `target` is the element the click was on (the div we hooked or an element
        // with in it), `currentTarget` is the div we hooked the event on
        let el = e.target;
        while (el && el !== e.currentTarget && el.tagName !== "B") {
            el = el.parentNode;
        }
        if (el && el.tagName === "B") {
            // ...do your state change...
        }
    }
    
    …以及在构造函数中绑定
    clickHandler
    的位置(而不是使用带有箭头函数的属性;原因:,):

    实例:

    let string=“Hello单击此处”;
    类示例扩展了React.Component{
    建造师(道具){
    超级(道具);
    此.state={
    点击次数:0
    };
    this.clickHandler=this.clickHandler.bind(this);
    }
    clickHandler(e){
    //'target'是单击的元素(我们钩住的div或元素)
    //其中,`currentTarget`是我们挂接事件的div
    //支持旧浏览器的版本:
    设el=e.target;
    而(el&&el!==e.currentTarget&&el.tagName!==B){
    el=el.parentNode;
    }
    如果(el&&el.tagName==“B”){
    this.setState(({clicks})=>({clicks:clicks+1}));
    }
    //现代浏览器的替代方案:
    /*
    常数el=e.目标最近(“B”);
    if(el&&e.currentTarget.contains(el)){
    this.setState(({clicks})=>({clicks:clicks+1}));
    }
    */
    }
    createMarkup=value=>{
    返回{uuuhtml:value};
    };
    render(){
    const{clicks}=this.state;
    返回[
    点击:{Clicks},
    ];
    }
    }
    ReactDOM.render(
    ,
    document.getElementById(“根”)
    );

    这里有一个简单的方法来满足您的需要。通过根据

    标记拆分字符串,您可以得到一个可映射的文本数组:

    类BoldText扩展React.Component{
    建造师(道具){
    超级(道具)
    此.state={
    输入:“订单ID 123收到的钱,哇,真的,太酷了,太疯狂了”
    }
    }
    boldClick=ev=>{
    console.log('clicked!')
    }
    render(){
    const{input}=this.state
    常量a=输入。拆分(“”)
    常量过滤器=/*/
    const text=input.split(过滤器)
    const clickable=filter.exec(输入)
    //
    返回(
    {a.map(t=>{
    常量[文本,粗体]=t.split(“”)
    返回{text}{bold}
    })}
    

    ) } } ReactDOM.render(,document.getElementById('root'))
    
    
    可以将HTML字符串转换为React组件

    使用transform回调函数,您可以使用JSX标记更新HTML字符串中的任何标记,并添加任何属性和事件侦听器

    我就是这样使用它的:

    ReactHtmlParser(item.value, {
        transform: (node) => {
            if (node.name === 'a' && node.attribs && node.attribs.href) {
                const matched = node.attribs.href.match(/^activity\/([0-9]+)$/i);
    
                if (matched && matched[1]) { // activity id
                    return <a
                            href={node.attribs.href}
                            onClick={(e) => {                                                            
                              e.preventDefault();                                                            
                              this.props.openActivityModal(matched[1]);
                            }}
                            >{node.children[0].data}</a>
                }
            }
        } 
    })
    
    reactHTMLPasser(item.value{
    变换:(节点)=>{
    if(node.name=='a'&&node.attribs&&node.attribs.href){
    const matched=node.attribs.href.match(/^activity\/([0-9]+)$/i);
    if(matched&&matched[1]){//活动id
    返回
    }
    }
    } 
    })
    
    为什么要这样做?用例是什么?它看起来像一个;如果可能的话,最好以不同的方式解决根本问题。是否应
    value
    this.createMarkup(value)中
    be
    string
    ?你不能这么做。通过
    危险的设置HTML,你将离开React作用域,你将无法调用它,即使你让它工作起来,也会很难看,可能有风险。如果你想让React处理某件事,请使用React。如果你想让你的
    标记更新状态,然后使用React正确创建它。在React中,返回的元素应该至少有一个父元素。我将拆分“string”分为两个字符串,元素应该作为react元素而不是字符串。虽然这种情况确实应该用另一种方法解决,但我认为使用
    refs
    对react初学者来说不是一个很好的建议,因为它被认为是一个不好的方法practice@Treycos-裁判对于他们所做的事情来说并不是不好的练习。但是正如我在评论t他问了这个问题,以及答案的开头(现在是结尾),不管潜在的问题是什么,它几乎肯定应该以不同的方式来解决。@Treycos-过了一个愉快的时刻,添加了一个更好的解决方案。:-)哦,哇,这是很多代码。Whi
    clickHandler(e) {
        // `target` is the element the click was on (the div we hooked or an element
        // with in it), `currentTarget` is the div we hooked the event on
        let el = e.target;
        while (el && el !== e.currentTarget && el.tagName !== "B") {
            el = el.parentNode;
        }
        if (el && el.tagName === "B") {
            // ...do your state change...
        }
    }
    
    this.clickHandler = this.clickHandler.bind(this);
    
    ReactHtmlParser(item.value, {
        transform: (node) => {
            if (node.name === 'a' && node.attribs && node.attribs.href) {
                const matched = node.attribs.href.match(/^activity\/([0-9]+)$/i);
    
                if (matched && matched[1]) { // activity id
                    return <a
                            href={node.attribs.href}
                            onClick={(e) => {                                                            
                              e.preventDefault();                                                            
                              this.props.openActivityModal(matched[1]);
                            }}
                            >{node.children[0].data}</a>
                }
            }
        } 
    })