jQuery是否使用正确的DOM操作来追加和创建元素?

时间:2013-12-03 15:46:41

标签: jquery dom

所以我刚遇到这个问题:
enter image description here

现在需要注意的是,尺寸是使用相同的代码打印出来的:

$graphContainer.append("<br/>dimensions: ");
var width = $graphContainer[0].offsetWidth, height = $graphContainer[0].offsetHeight;       
$graphContainer.append(width + 'x' + height);

红色的DIV就是它自己的$graphContainer。函数的调用方式如下:

        s.load();
        setTimeout(function() {
            s.load()
        }, 350);

s是我正在建造的对象。 (如果我使用300毫秒,那么两者都是800x30,所以它在300-350ms之间。)

现在DOM顺序是正确的,并且在调用此函数之前使用jQuery将元素附加到DOM中。 (有点复杂的逻辑,希望你能接受我的话,而不必看到漏洞代码)。

我想我实际上知道这里有什么,如果你使用innerHTML来附加内容,那么它需要一段时间才能在DOM中完全可用,这可能会导致像这样的幻像。现在我所谈论的时间表是在几毫秒内,但对我来说,有一个政策永远不会使用innerHTML来附加或制作元素。

事情是,对象中使用的所有DOM元素和完成的DOM操作都是使用jQuery代码(如$('<div>'))来创建元素,$container.append($child)用于追加子元素。

我总是认为jQuery做了正确的DOM操作 这是不是真的,他们广泛使用innerHTML? 或者我错过了一些东西,这可能是300ms延迟有点长,因为它是innerHTML问题?

我目前正在使用jQuery 1.9.1

以防万一这是获得此结果的代码(它是一个jQuery插件):

if (typeof jQuery != 'function') {
    throw "The CommoditiesPeersIndices is a jQuery plugin i.e. jQuery needs to be defined first";
}

(function ($) {
    /*
        Built with jQuery 1.9.1 in mind.
        Creates the [CommoditiesPeersIndices] Object
    */


var CommoditiesPeersIndices = function(Settings) {
/*
    Binds all of the tools objects into a single object and manages them
*/
    var 
        CLASS_NAME = 'CommoditiesPeersIndices' //the CSS root Class name that will be applied to all the objects
    ;

    this.$root = $('<div>'); //the root of the object

    var This = this
        ,DefaultSettings = {
            //$container : null //the jQuery object into with the tool will be built
            parentClassName : '' //the parent class name name of the parent object that will be appended to this object
        }
    ;

    var s; //temp variale for the test small graph

    function _init() {
        //makes sure that the Settings object has all of the settings
        mergeSettings(Settings, DefaultSettings);
        CLASS_NAME = Settings.parentClassName + CLASS_NAME;

        s = new SmallGraphObject({
            parentClassName : CLASS_NAME + '-'
        });
        This.$root.append(s.$root);
    }

    this.load = function() {


        s.load();
        setTimeout(function() {
            s.load()
        }, 350);


    };

    function mergeSettings(targetObject, sourceObj) {
    /*
        Used to merge the DefaultSettings with the Settings object. Basically the targetObject will get all of the sourceObjects values that are missing from the target object or are not of the same type as the sourceObject value.
    */
        var name, targetType;
        if(typeof targetObject == 'object' && targetObject  != null) {
            //merges the user Settings object with the Default SettingsObject i.e. DefaultSettings
            for(name in sourceObj) {
                targetType = typeof targetObject[name];
                switch(targetType) {
                    case 'object':
                        if(targetType == null) {
                            targetObject[name] = Utility.copyObject(sourceObj[name]);
                        } else {
                            mergeSettings(targetObject[name], sourceObj[name])
                        }
                        break;
                    default:
                        if(typeof sourceObj[name] != typeof targetObject[name]) {
                            targetObject[name] = sourceObj[name];
                        }
                        break;
                }
            }
        } else {
            targetObject = Utility.copyObject(sourceObj);
        }
    }   

    _init();
};var SmallGraphObject = function(Settings) {
/*
    The single small graph object on the page, holds the graph + the enlarge button
*/
    var 
        CLASS_NAME = 'SmallGraph'
    ;

    this.$root = $('<div>'); 

    var This = this
        ,DefaultSettings = {
            instrumentID : 1031004 //the instrument ID of the instrument who's data will be displayed.
            ,parentClassName : '' //the parent class name name of the parent object that will be appended to this object
            ,startDate : new Date()
            ,decimalPlaces : 2 //the number of decimal places the series will show
        }
        ,$graphContainer = $('<div>') //the highchart's container
        ,$header = $('<div>') //the header that holds the name and the enlarge button

        ,$container = $('<div>') //the container object of the [SmallGraph] to with you can place CSS
    ;

    function _init() {
        //makes sure that the Settings object has all of the settings
        mergeSettings(Settings, DefaultSettings);

        CLASS_NAME = Settings.parentClassName + CLASS_NAME;

        $container.addClass(CLASS_NAME + 'Container')
            .append($header.addClass(CLASS_NAME + '-Header'))
            .append($graphContainer.addClass(CLASS_NAME + '-Graph'))
        ;
        This.$root.addClass(CLASS_NAME).append($container);

        $header.text('Heading');
    }

    this.load = function() {
    /*
        Loads the series data from the server.
    */

        $graphContainer.append("<br/>dimensions: ");
        var width = $graphContainer[0].offsetWidth, height = $graphContainer[0].offsetHeight;       
        $graphContainer.append(width + 'x' + height);
    };

    function mergeSettings(targetObject, sourceObj) {
    /*
        Used to merge the DefaultSettings with the Settings object. Basically the targetObject will get all of the sourceObjects values that are missing from the target object or are not of the same type as the sourceObject value.
    */
        var name, targetType;
        if(typeof targetObject == 'object' && targetObject  != null) {
            //merges the user Settings object with the Default SettingsObject i.e. DefaultSettings
            for(name in sourceObj) {
                targetType = typeof targetObject[name];
                switch(targetType) {
                    case 'object':
                        if(targetType == null) {
                            targetObject[name] = Utility.copyObject(sourceObj[name]);
                        } else {
                            mergeSettings(targetObject[name], sourceObj[name])
                        }
                        break;
                    default:
                        if(typeof sourceObj[name] != typeof targetObject[name]) {
                            targetObject[name] = sourceObj[name];
                        }
                        break;
                }
            }
        } else {
            targetObject = Utility.copyObject(sourceObj);
        }
    }

    _init();
};

    $.fn.CommoditiesPeersIndices = function() {
    /*
        Creates a new instance of [CommoditiesPeersIndices]
    */    
        var Main = new CommoditiesPeersIndices({
                parentClassName : 'Tools-'
            })
            ,$head = $('head')    
        ;

        $head.append('<link rel="stylesheet" type="text/css" href="http://localhost:60226/Content/jQueryComponent.css" />');
        $head.append('<link rel="stylesheet" type="text/css" href="http://localhost:60226/Config/Company/test/test.css" />');

        this.append(Main.$root);
        Main.load();

        return this;
    };

}(jQuery));

使用这个CSS:

.Tools-CommoditiesPeersIndices-SmallGraph {
    width: 300px;

}
.Tools-CommoditiesPeersIndices-SmallGraph-Graph {
    height: 150px;
    background: #f00;
}

1 个答案:

答案 0 :(得分:1)

关于API上jQuery的机制有一些解释。这就是文档关于将节点作为参数传递的说法,例如: $('<div>')

  

如果HTML比没有属性的单个标签更复杂,那么   在上面的例子中,元素的实际创建是   由浏览器的innerHTML机制处理。在大多数情况下,jQuery   创建一个新元素并设置的innerHTML属性   传入的HTML片段的元素。当参数有。时   一个标签(带有可选的结束标签或快速关闭) - $(“”)或$(“”),$(“”)或$(“”) - jQuery创建   使用本机JavaScript createElement()函数的元素。

因此,如果你投入的不仅仅是一个标签,那么innerHTML就会开始:

var foo = $("<div>");                   // this will use createElement
var bar = $("<div><p>hello</p></div>"); // innerHTML will be used here
var doh = $("<div class='hello'>");     // also innerHTML here...

我也遇到过jQuery创建元素太慢的问题(特别是在Internet Explorer上),所以我继续使用本机函数createElementcreateTextNode,我的上帝吧突如其来的快死了!