避免双循环插入节点并激活它们?

时间:2014-03-26 17:37:42

标签: javascript jquery

我遇到的一个常见问题是需要在循环中创建多个DOM节点,然后通过应用插件,事件处理程序或类似方式以某种方式激活这些节点。激活步骤要求元素实际上先存在。

所以你最终做了类似的事情:

// Loop 1: Create the nodes
var HTML = '<tr id="UID">';
for(var k in Fields){ // Fields is an object!
  HTML += '<td>';
  HTML += '<input class="ActivateMe"/>';
  HTML += '</td>';
}
var HTML += '</tr>';
$TableBody.children('tr').first().before(HTML);


// Loop 2: Activate the new nodes
$('#'+UID).children('td').children('.ActivateMe').each(function(index){
  $(this).InitSomePlugin();
});

上面的代码针对这个问题进行了简化,但假设给定单元格中的每个元素可以不同(可能是输入,可能是div),也可能需要不同的插件(也许它是一个颜色选择器,也许这是一个组合框)。

是否可以避免两次循环数据集并一次性执行插入和激活?我认为可以通过在第一个循环中附加节点来实现,这也可以允许在第一个循环中激活。但通常认为在循环中使用append而不是将所有HTML存储在var中并立即附加所有HTML是不好的做法。同时,在同一组数据上循环两次似乎效率也很低。在对性能影响最小的情况下处理此方案的最佳方法是什么?

3 个答案:

答案 0 :(得分:2)

是。不要构建冗长的HTML字符串,而是在第一个循环中以编程方式创建元素,以便您可以直接在其上实例化插件:

var $TableBody = …,
var $row = $('<tr>', {id:UID});
for(var k in Fields) { // sure that Fields is an object?
                       // For an array, use a normal for loop
  var $cell = $('<td>');
  var $input = $('<input class="ActivateMe"/>');
  $input.InitSomePlugin();
  $input.appendTo($cell);
  $cell.appendTo($row);
}
$row.prependTo($TableBody);

在调用.InitSomePlugin()之前,您可能需要执行附加操作。您也可能希望嵌套调用并使用链接来缩短代码:

var $row = $('<tr>', {id:UID}).prependTo(…);
for(var k in Fields)
  $('<input class="ActivateMe"/>')
    .appendTo($('<td>').appendTo($row))
    .InitSomePlugin();

答案 1 :(得分:-1)

由于激活步骤要求元素已经存在且(可能)在DOM中,因此您只有两个选择:

1)您可以单独创建每个DOM元素(使用document.creatElement()或jQuery&#39; s $(html)之类的东西),这样您就可以保存DOM对象引用,以后可以用来初始化插件

2)你可以像你一样建立一串HTML。插入该字符串,让浏览器为您创建所有元素,然后您必须找到适当的DOM元素才能初始化插件。

测试表明,通常情况下,浏览器在给定HTML字符串时会更快地创建大量HTML对象,而不是手动创建和插入单个DOM对象,因此使用HTML字符串没有特别的问题。 / p>

这里没有100%正确或错误的答案。除非您有数百到数千个DOM元素,否则性能可能不是主要问题。我倾向于选择最简洁,最简单的代码。

在您的情况下,您必须迭代Fields对象,这样您才能避免这种情况。您必须找到表格的第一行,这样才能避免这种情况。

如果您已经决定构建HTML字符串是编写代码的最便捷的方法(它可能就在这里),那么您就无法重新构建需要激活的对象。 DOM。

你可以尽可能高效地处理事情。

这里有一点精简,与基本理念保持一致:

// create the new rows
var HTML = '<tr id="UID">';
for(var k in Fields) {
    HTML += '<td>' + '<input class="ActivateMe"/>'+ '</td>';
}
HTML += '</tr>';

// create an insert new content, save reference to new content
var newObj = $(HTML);
$TableBody.prepend(newObj);

// now activate the plugin on the appropriate objects in the new content
newObj.find(".ActivateMe").InitSomePlugin();

简化步骤:

  1. 在一个语句中创建每个单元格而不是三个
  2. 当您创建新的行对象时,请保留对它的引用,以便我们不必再次找到它。
  3. 添加新内容时,请使用.prepend()将其设为第一行,而不是查找所有行并选择第一行
  4. 如果您在每个对象上运行相同的jQuery方法,那么在初始化插件的情况下,就不需要.each()循环。你可以这样:newObj.find(".ActivateMe").InitSomePlugin();没有.each()

  5. 您也可以自己创建DOM对象,而不是使用HTML字符串并跟踪需要激活的对象,以便不必再次找到它们:

    // create the new rows
    var row = $('<tr id="UID"></tr>'), input, item, activates = [];
    for(var k in Fields) {
        item = $('<td>');
        input = $('<input class="ActivateMe"/>')
        activates.push(input);
        item.append(input);
        row.append(item);
    }
    
    // insert row into table
    $TableBody.prepend(row);
    
    // now activate the plugin on the appropriate objects that are now inserted
    $(activates).InitSomePlugin();
    

    纯粹主义者可能会喜欢&#34;第二个选项比第一个选项更好,因为它没有使用HTML字符串,但除非你做了数百到数千次,所以性能是最重要的(在这种情况下你必须这样做)测试哪种方法实际上表现更好并诊断为什么),我不能老实说第二种方法比第一方更好。我喜欢第一个编码简单,在特定表中找到一些类对象,这不是一个昂贵的操作。

答案 2 :(得分:-1)

$tableBody = $('table');

// Prepare an DOM object but don't append it to DOM yet.
$tr = $('<tr></tr>',{
    id: "UID"
});

// Loop over any condition you would see fit.
for(var i = 0; i < 2; ++i) {
    $td = $('<td></td>',{
        // Prepare your input element with your event bound to it
        "html": $('<input/>', {"class": "ActivateMe"}).InitSomePlugin();
    });
    // append your td element
    $tr.append($td);
}

// Add your tr element to the beginning of your table with prepand method.
$tableBody.prepend($tr);