在将它放入DOM之前初始化jQuery对象(元素)

时间:2012-01-20 07:46:56

标签: javascript jquery html dom

因此,对于我正在开发的项目,我需要让用户选择器中的用户可以按网络排序。我这样做的当前方式是创建用户:

clone += '<li class="'+ this.gender +'" data-id="'+ this._id +'">';
clone += '<img src="'+ this.image +'" />';
clone += '<span>'+ this.name +'</span>';
clone += '</li>';

然后有一个jQuery对象,其中键是网络名称,值是用户ID数组,如:

{
  Network 1: [1,2,3,4]
  Network 2: [5,6,7,8]
}

然后,当选择网络时,我对所有li元素进行排序并将它们与id数组匹配,如果它不包含id,则隐藏li元素,如下所示:

for(var i = 0, n = education_ids[network].length;i < n;i++){
   $('.friends-list li[data-id='+ education_ids[network][i]+']').removeClass('chosen_network');
}

不幸的是,它的效率非常低,因为基本上对于循环的每次迭代,jQuery选择器都会遍历所有li元素,因此如果网络中有1000个朋友和100个ID,那就是100个1000步迭代。

作为这个问题的解决方案,我想我可能能够将jQuery对象添加到数组而不是id,这样我就可以迭代它们并添加类(减少迭代次数1000x)。以下是我目前正在努力做到的事情:

clone += '<li class="'+ this.gender +'" data-id="'+ this._id +'">';
clone += '<img src="'+ this.image +'" />';
clone += '<span>'+ this.name +'</span>';
clone += '</li>';

if(this.education){
    for(var i = 0, n = this.education.length; i < n ; i++){
    if(education[this.education[i].school.name]){
       education[this.education[i].school.name]++;
       education_ids[this.education[i].school.name].push($(clone));
    } else {
        education[this.education[i].school.name] = 1;
        education_ids[this.education[i].school.name] = [$(clone)];
    }
}
}

相关部分是我:

.push($(clone)

或通过执行以下操作初始化数组:

[$(clone)]

不幸的是,这种技术不起作用,因为在我的程序中,元素实际上还没有添加到DOM中。所以,我的问题如下:

是否有可能在将这些jQuery引用放入DOM之前初始化它们,如果是这样,我该怎么做?

而且,如果我不能这样做,你能否想到一种更有效的方法来解决这个问题。

仅供参考,我试图加快速度,因为使用当前策略,循环会将DOM冻结1到2秒之间的任何时间 - 这对用户来说并不完全是理想的体验。

非常感谢您提供任何帮助!

编辑:取得了进展,但遇到了错误!

好的,所以我取得了一些进展。使用jQuery选择器实际上是有效的,所以现在我正在做:

    clone += '<li class="'+ this.gender +'" data-id="'+ this._id +'">';
    clone += '<img src="'+ this.image +'" />';
    clone += '<span>'+ this.name +'</span>';
    clone += '</li>';

    clone = $(clone)

    if(this.education){
        for(var i = 0, n = this.education.length; i < n ; i++){
            if(education[this.education[i].school.name]){
                education[this.education[i].school.name]++;
                education_ids[this.education[i].school.name].push(clone);
            } else {
                education[this.education[i].school.name] = 1;
                education_ids[this.education[i].school.name] = [clone];
            }
        }
    }

placeholder.push(clone);

然后循环过所有的朋友,

$('.friends-list').append(placeholder).fadeIn();

我认为这应该有效,但现在我得到了:

Uncaught Error: NOT_FOUND_ERR: DOM Exception 8

思想?

编辑:更多进度,修正了错误,但排序不正常

好的,所以我通过将占位符切换到像@Artimuz那样的空div来修复错误,但现在排序不起作用。所以,基本上我是这样的:

if("network is clicked and it was already selected") {
    for(var person in education_ids[network]){
        person.removeClass('chosen_network');
    }
} else //if it wasn't already selected {
     for(var person in education_ids[network]){
        person.addClass('chosen_network').removeClass('disabled');
}
}

不幸的是,这不起作用。我得到了:

Uncaught TypeError: Object 0 has no method 'addClass'

所以,我再一次问:想法?

3 个答案:

答案 0 :(得分:2)

任何javascript中最慢的部分都是触及DOM。存储您的用户:

var users = [
    {
        name : "dave",
        gender : "male",
        image : "omg.jpg"
    }
];

存储您的网络(假设您的网络数量少于用户):

var networks = [
    [2,5,8]
];

在需要时适当绘制:

var html = "";
for(var i = networks[current].length; i--;){
    var id = networks[current][i];
    html += '<li class="'+ users[id].gender +'" data-id="'+ id +'">';
    html += '    <img src="'+ users[id].image +'" />';
    html += '    <span>'+ users[id].name +'</span>';
    html += '</li>';
}
$(container).html(html);

这样,您可以在每个用户上迭代一次,即用户的纯数据。并且您触摸DOM一次以绘制所需的所有内容。

这具有重绘所有当前显示的用户的缺点,但如果这是一个问题(例如,如果大多数人都在所有网络中),则可以修改解决方案以缓存已经绘制了哪些用户,并添加新用户更加分散。

答案 1 :(得分:2)

好的,所以我会尝试总结一下你的一些错误:

第一个错误

不知道你的问题是什么。对我有用。

jsfiddle.net/3xqx5

对于NOT_FOUND_ERR例外

只是你试图向DOM添加一个纯{j}对象array。 JQuery.append需要一个jQuery对象或一个DOM元素!因此,您可以将项目放在占位符<div>中,或者迭代数组并逐个添加项目。

jsfiddle.net/3xqx5/1

对于上一个错误Object 0 has no method 'addClass'

您所做的for语句不一致,至少因为它在每次迭代时都会复制每个项目。通过执行for(var i=0; i < a.length; i++)

直接处理数组元素

jsfiddle.net/3xqx5/2

答案 2 :(得分:1)

使用字符串连接构建HTML非常糟糕,请避免这种情况。

根据@ Sinetheta的数据结构

var template = [
    "<li>",
        "<img></img>",
        "<span></span>",
    "</li>"
].join("");

var nodes = [];
for(var i = networks[current].length; i--;){
    var id = networks[current][i],
        user = users[id];

    var li = $(template);
    li.addClass(user.gender);
    li.data("id", id);

    var children = node.children();
    children.eq(0).prop("src", user.image);
    children.eq(1).text(user.name);

    nodes.push(li);
}

$.each(nodes, function (_, node) {
    $(container).append(node);
});