react html to dom,React:DOM操作

本文介绍了React虚拟DOM的概念,强调了其在避免直接操作DOM的优势。讲解了如何通过ref属性和ReactDOM.findDOMNode()方法在必要时访问底层DOM,以及如何整合非React类库保持状态同步。重点突出了在React生命周期中的正确使用时机。
摘要由CSDN通过智能技术生成

虚拟DOM(virtual DOM)是React的一大亮点。正是因为虚拟DOm,在大多数的应用场景中,我们都只要关注设置组件的状态(setState),不需要直接操作DOM。

那么虚拟DOM到底是什么呢?

其实,虚拟DOM(virtual DOM)是一个模拟DOM树的JavaScript对象。React使用虚拟DOM来渲染UI,当组件状态state有更新时,React会自动调用组件的render方法重新渲染整个组件的UI。

大多数时候,我们都应该呆在React的“虚拟浏览器”的世界里,因为它性能更加好,并且容易思考。但是,在某些情况下,为了实现某些需要,我们不得不去操作底层的DOM。比如:需要与一个没有使用React的第三方类库进行整合,或者执行一个React没有原生支持的操作(canvas)。

我们需要了解ReactDOM.render组件返回的是什么?

它会返回对组件的引用,也就是组件实例(对于无状态组件来说,返回null)。

注意:JSX返回的不是组件实例,它只是一个ReactElement对象。

在React内,它提供了一个可用于处理受其自身控制的DOM节点的方法,不过要注意的是,这些方法仅在组件声明周期的特定阶段才能被访问到。

1、refs

要访问受React控制的DOM节点,首先必须能够访问到负责控制这些DOM的组件,我们可以通过为子组件添加一个ref属性来实现。

var MyInput = React.createClass({

render: function(){

returen (

);

}

});

为子组件添加了ref属性后,我们就可以通过this.refs.myInput访问到组件了。

this返回的是当前组件。

注意:赋给每个子组件的ref值在所有子组件中必须是唯一的,也可以说是全局唯一。

到这里,我们已经可以访问到需要的子组件了,然后就可以通过它的getDOMNode()方法来访问到底层的DOM节点了。

但是请注意,我们不能在render方法中使用getDOMNode()方法,只有在render方法执行之后,并且react已经完成了DOM的更新,才能通过 this.refs.city.getDOMNode() 来拿到原生的DOM元素,也可以这样说,getDOMNode()仅在挂载的组件上有效(挂载:组件已经被放进DOM中),否则抛出异常。

一般我们会在 componentDidMount 事件回调中使用 getDOMNode 方法,当然,componentDidMount内部并不是getDOMNode方法的唯一执行环境。事件处理器也是在组件挂载后触发的,所以也可以在事件处理器中调用getDOMNode()方法。

var MyInput = React.createClass({

render: function(){

return ();

},

handleKeyUp: function(){

var input = this.refs.myInput;

console.log(input.value);

},

componentDidMount: function(){

console.log(this.refs.myInput);

}

});

ReactDOM.render(

,

document.body

);

上面的代码中,给input添加了一个keyup事件处理器,在handleKeyUp()方法里,我们也可以用this.refs.myInput访问到对应的input元素。

每一个挂载的React组件都有一个 getDOMNode() 方法。

如果不了解React的生命周期,可以看这里:React:组件的生命周期

特别注意:(getDOMNode()方法在v0.14版本中使用会报提醒,而在 v0.15版本中已经移除了)。因此,如果你使用的是 v0.15版本及以上的,this.refs.myInput获取到的已经是对应的DOM元素了,不过refs的表现和行为还是和之前的一致的。

2、ReactDOM.findDOMNode()

除了使用refs外,我们还可以使用react-dom提供的findDOMNode()方法拿到组件对应的DOM元素。

var MyInput = React.createClass({

render: function(){

return ();

},

handleKeyUp: function(){

var input = ReactDOM.findDOMNode(this);

//或者

input = ReactDOM.findDOMNode(this.refs.myInput);

console.log(input.value);

}

});

ReactDOM.render(

,

document.body

);

3、整合非React类库

要使用非React类库,保持它们的状态和React的状态之间的同步是成功整合的关键。

假如我们需要使用一个autocomplete类库:

(function(){

var autocomplete = function(params){

params = params || {};

if(!params.target) return;

var parent = params.target;

var data = params.data;

var list = '';

for(var i = 0; i < params.data.length; i++){

list += '

' + params.data[i] + '';

}

parent.innerHTML = list;

if(params.events){

parent.addEventListener('click',function(e){

if(e.target.nodeName == 'LI'){

params.events.select(e.target.textContent);

}

});

}

};

window.autocomplete = autocomplete;

})();

调用示例代码:

autocomplte({

target: document.getElementById('cities'),

data: [

'广州','北京','深圳'

],

events: {

select: function(city){

alert('你选择的城市是' + city);

}

}

});

上面的autocomplete函数需要一个目标DOM节点、一个用作数据展现的字符串清单,以及一些事件监听器。

接下来,我们需要创建一个使用这两个库的React组件,然后需要添加一个componentDidMount处理器,在这个处理器内,可以将autocompleteTarget所指向子组件的底层DOM节点来连接这两个接口:

var AutocompleteCities = React.createClass({

render: function(){

return (

},

getDefaultProps: function(){

return {

data: ['广州','北京','深圳']

};

},

handleSelect: function(city){

alert('你选择的城市是' + city);

},

componentDidMount: function(){

autocomplete({

target: this.refs.autocompleteTarget,  //也可以使用ReactDOM.findDOMNode(this.refs.autocompleteTarget)

data: this.props.data,

events: {

select: this.handleSelect

}

});

}

});

注意:componentDidMount方法只会为每个DOM节点调用一次。因此我们不用担心一个节点上两次调用autocomplete方法是否会有副作用。

对于简单的插件,最好是通过将其重写为React组件的形式来封装它。

总结

当仅使用虚拟DOM无法满足需求时,可以考虑ref属性,它允许访问指定的元素

在render方法执行之后,并且react已经完成了DOM的更新(一般是componentDidMount执行后)时,可以使用this.refs.name或者ReactDOM.findDOMNode()方法来访问底层的DOM节点。

可以将简单的第三方类库(非React类库)重写为React组件的形式来封装它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值