在 dangerouslySetInnerHTML 中从 onclick 调用 React 组件函数
Call React Component Function from onclick in dangerouslySetInnerHTML
这里是 React 新手。我有一个 contenteditable
div,其中 dangerouslySetInnerHTML
作为 child,因为我需要在运行时格式化用户输入的任何内容。在特定范围内单击 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() 方法。
试试这个:
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} />
);
}
如果您希望您的跨度响应点击事件,您应该仅在您的组件重新呈现后分配事件处理程序(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 树。
我最近也有类似的需求。 React 应用程序被赋予了一个 html 块,其中包含需要转换为 onClick 事件的 href 属性,以便我们可以在 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)
}
这里是 React 新手。我有一个 contenteditable
div,其中 dangerouslySetInnerHTML
作为 child,因为我需要在运行时格式化用户输入的任何内容。在特定范围内单击 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() 方法。
试试这个:
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} />
);
}
如果您希望您的跨度响应点击事件,您应该仅在您的组件重新呈现后分配事件处理程序(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 树。
我最近也有类似的需求。 React 应用程序被赋予了一个 html 块,其中包含需要转换为 onClick 事件的 href 属性,以便我们可以在 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)
}