Инициализируйте объект jQuery (элемент) перед размещением его в DOM - PullRequest
2 голосов
/ 20 января 2012

Итак, для проекта, над которым я работаю, мне нужно сделать так, чтобы пользователи в селекторе пользователей сортировались по сети.В настоящее время я делаю это, создавая пользователя:

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

Затем имея объект jQuery, ключом которого является сетевое имя, а значением является массив идентификаторов пользователей, например:

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

Затем, когда сеть выбрана, я перебираю все элементы li и сопоставляю их с массивом идентификаторов, а если он не содержит идентификатор, скрываю элемент 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 идентификаторов, это 100 итераций 1000 шагов.

В качестве решения этой проблемы я подумал, что смогу добавить объекты jQuery в массив, а не в идентификаторы, чтобы я мог просто перебирать их и добавлять классы (сокращая количество итераций в 1000 раз).Вот как я сейчас пытаюсь это сделать:

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

Мысли?

РЕДАКТИРОВАТЬ: больше прогресса, исправлена ​​ошибка, но сортировка не работает

ОК,поэтому я исправил ошибку, переключив местозаполнитель на пустой div, как @Artimuz, но теперь сортировка не работает.Итак, в основном я сортирую так:

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 ]

2 голосов
/ 20 января 2012

ОК, поэтому я попытаюсь обобщить некоторые ваши ошибки здесь:

За первую ошибку

Понятия не имею, в чем была ваша проблема. Для меня это сработало.

jsfiddle.net / 3xqx5

Для NOT_FOUND_ERR исключения

Просто вы пытались добавить array, чистый объект javascript, в DOM. 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 голосов
/ 20 января 2012

Самая медленная часть любого 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 голос
/ 20 января 2012

Сборка 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);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...