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