rwson

rwson

一个前端开发

React中的DOM操作

大多数情况下,React的虚拟DOM已经可以创建我们想要的用户体验,而根本不需要直接操作底层真实的DOM,通过组件的复合,把负责的交互聚合为呈现给用户的连贯整体。

但是在某些情况下,比如与一个没有使用React的第三类库的整合,或者执行一个React没有原生支持的操作等等,我们就不得不去操作底层DOM来达到我们的目的。

DOM操作

访问受控制的DOM节点

React提供了一个受其自身控制的方法,这些方法只有在生命周期的相关方法里才有效。我们可以给组件的相关元素添加一个ref属性来实现。

var CanvasComponent = React.createClass({
    render:function(){
        return (
            <canvas ref="canvasEle" />
        );
    }
});

这样就可以通过this.refs.canvasEle来访问到这个canvas节点了,需要注意的是这里的ref属性必须是唯一的,如果定义了相同的ref也是"canvasEle",那么操作将无效。

一旦访问到了该元素,那么就可以通过getDOMNode()方法来访问底层的DOM节点,需要注意的是,不要在render方法中尝试用该方法,因为在render方法执行完之前,组件还未挂载,该DOM节点不是最有效的,所以可能会报异常。

所以要在组件被挂载后使用,比如componentDidMount或者一些用户操作后的事件处理函数,就像下面这样:

var CanvasComponent = React.createClass({
    render:function(){
        return (
            <canvas ref="canvasEle" />
        );
    },
    
    componentDidMount:function(){
        var oCanvas = this.refs.canvasEle.getNode();
        //  现在oCanvas就是我们的canvas节点,可以调用canvas下的相关方法来进行操作
    }
}); 

React的refs和getDOMNode很强大,但是使用它们可能会导致React在性能上的一些问题,所以我们不到在没有其他方式的时候,尽量不要用它们来解决问题。

#####整合非React类库

很多成熟的javaScript类库并没有使用React构建,此时就需要我们自己来进行整合。

比如现在要使用一个autocomplete插件,包含下面的基础代码:

autocomplete({
    target:document.getElementById("select"),
    data:[
        "option1","option2","option2"
    ],
    events:{
        select:function(item){
            alert("你选择了" + item);
        }
    }
});

这个类库需要一个DOM节点,一个数组,一个事件的相关对象,所以,这里就用到了DOM操作,刚才提到,在React中使用DOM操作要在组件挂载完成后或一些事件处理函数中完成。

var SelectComponent = React.createClass({
    getDefaultProps:function(){
        return {
            data:[
                    "option1","option2","option2"
                ]
        };
    },
    render:function(){
        return (
            <div id="select" ref="autoCompleteDOM"></div>
        );
    },
    handleSelect:function(item){
        alert("你选择了" + item);
    },
    componentDidMount:function(){
        autocomplete({
            target:this.refs.autoCompleteDOM.getDOMNode(),
            data:this.props.data,
            events:{
                select:this.handleSelect
            }
        });
    }
});

现在把autocomplete引入到React中了,但是这样还不够,要知道,在这个组件被移除了怎么办,所以引入外部插件时一般需要注意在组件类中再实现一个componentWillUnmount的方法,这样在组件被移除,它会对自身进行清理,从而避免内存泄露等性能问题。

#####侵入式插件

在整合非React类库的时候,我们希望整合的类库仅仅操作的是组件的子元素,但是有时并非如此,此时我们就需要把这些额外的操作在React中规避掉,防止出现DOM被意外修改的错误。处理这种问题,最有效的方法就是把DOM的操控权完全给我们自己,而不是给这些类库。