因此,对于我正在开发的项目,我需要让用户选择器中的用户可以按网络排序。我这样做的当前方式是创建用户:
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'
所以,我再一次问:想法?
答案 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)
好的,所以我会尝试总结一下你的一些错误:
不知道你的问题是什么。对我有用。
NOT_FOUND_ERR
例外只是你试图向DOM添加一个纯{j}对象array
。 JQuery.append需要一个jQuery对象或一个DOM元素!因此,您可以将项目放在占位符<div>
中,或者迭代数组并逐个添加项目。
Object 0 has no method 'addClass'
您所做的for
语句不一致,至少因为它在每次迭代时都会复制每个项目。通过执行for(var i=0; i < a.length; i++)
答案 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);
});