2015-07-30 3 views
0

У меня очень большой и сложный плагин jQuery, который я буду избегать публиковать здесь для простоты. Моя проблема очень проста, и я уменьшить его только к соответствующему коду:Отложенный рендеринг CSS при работе Javascript

У меня есть событие щелчка прилагается к набору кнопок:

$("ul.tick-boxes button").click(function(event) { 
    event.preventDefault(); 
    $("ul.product-grid").addClass("loading"); 
    $(this).toggleClass("active"); 
    $theElement.trigger("filterOptionsChanged"); 
}); 

Если вы идете по этой ссылке, вы можете увидеть это в действии в левой боковой панели:

http://mazer.com/collections/refrigerator?preview_theme_id=22019779

Вот CSS, который производит галочку при нажатии кнопки:

ul.tick-boxes button.active .tick-box::after { 
    content: "\e603"; 
    font-family: "custom-icons"; 
    color: #51425d; 
    top: 2px; 
    left: 2px; 
    font-size: 0.75rem; 
    position: absolute; 
} 

Если ваш компьютер работает так же медленно, как и мой, то, когда вы нажимаете эти параметры фильтра, требуется «галочка» в «галочке». Если вы не видите этого, попробуйте разоблачить его, что для меня занимает значительно больше времени. Временной момент, когда «тик» заметно визуализируется, всегда совпадает с восстановлением и рендерингом сетки продукта. Я не размещал код для управления сетью продуктов, но вы можете знать, что строка $theElement.trigger("filterOptionsChanged") запускает множество массивов и обработки объектов для создания фрагмента документа нового списка продуктов и обновляет DOM в конце. Я понимаю, что это может занять секунду, это не моя проблема. Но я не понимаю, почему мои «галочки» ждут, пока код этого события не будет завершен для рендеринга. Согласно моему css, все, что мне нужно, это класс active на кнопке, и этот код запускается на одну строку выше, вызывая событие «filterOptionsChanged», поэтому он должен срабатывать до того, как произойдут изменения в сетке продукта.

Теперь. Если я открою свой инспектор в хроме, я могу увидеть активные классы, которые переключаются мгновенно на клик, до обновления сетки продукта. Тем не менее, css, который добавляет галочку, не захватывает активный класс в элементе до тех пор, пока не завершится мой код «filterOptionsChanged».

Моя первая попытка решить проблему будет опубликована ниже. Я хорошо прочитал об «затратности» псевдоселекторов css. Это, по сути, браузер, это похоже на манипуляцию dom каждый раз, когда создается элемент ::after. Поэтому я тогда пишу этот CSS:

ul.tick-boxes button .tick-box::after { 
    content: "\e603"; 
    font-family: "custom-icons"; 
    color: #51425d; 
    top: 2px; 
    left: 2px; 
    font-size: 0.75rem; 
    position: absolute; 
    opacity: 0; 
} 

ul.tick-boxes button.active .tick-box::after { 
    opacity: 1; 
} 

Так теперь ::after элемент всегда существует с самого начала, все расходы рендеринга оплачивается в самом начале, так что моя мысль была, теперь, когда я нажимаю на эту кнопку, клещ уже там, мы просто даем ему непрозрачность 1. Не фиксировали задержку.

Теперь я пытаюсь полностью удалить триггер события filterOptionsChanged. Это заставляет весь мой плагин сортировки перестать работать, но мне все равно, потому что я хочу понять, что вызывает проблему. Когда я удаляю этот триггер событий, кнопки и css визуализируются мгновенно. Больше никаких проблем.

У меня есть смутное представление о том, что, если событие click может быть быстрым без триггера события, мне нужен способ разделить их. Сначала добавьте класс active, затем запустите «filterOptionsChanged». Я думаю, хорошо, jQuery Deferreds. Вот этот код:

$("ul.tick-boxes button").click(function(event) { 
    event.preventDefault(); 
    var showLoading = jQuery.Deferred(); 
    $("ul.product-grid").addClass("loading"); 
    $(this).toggleClass("active"); 
    showLoading.resolve(); 
    $.when(showLoading).done(function() { 
     $theElement.trigger("filterOptionsChanged"); 
    }); 
}); 

Так showLoading является пустым Отложенным, я затем добавить свои классы для галочек, чтобы показать, то я разрешаю отсроченным. Теперь я говорю, когда showLoading выполняется, то выполняйте всю манипуляцию с сеткой продукта. Не делайте этого в одно и то же время, javascript, дождитесь окончания, а затем выполните другой. Все равно нет. Есть идеи?

+0

['window.requestAnimationFrame'] (https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) может быть полезно –

+0

Я не могу сказать, что делает ваш код, но я не вижу никаких HTTP-запросов. Нет причин для этого быть медленным, но, не видя этого, я не могу предложить никаких предложений. Работа по созданию даже большого фрагмента страницы должна занимать гораздо меньше времени (если сделано правильно) на современном компьютере. Однако есть много дорогих вещей, которых следует избегать. – Pointy

+0

Трудно сказать, потому что оно уменьшено, но я держу пари реальные проблемы, как в этом «большом быстродействующем фильтре». Кажется, не так быстро. – Pointy

ответ

1

В соответствии с this все вызовы функций в JavaScript блокируют пользовательский интерфейс до их завершения; Я бы сказал, что это включает вызов функции , чтобы начать событие click. Дешевое решение может быть заменить триггер с чем-то вроде:

setTimeout(function() { $theElement.trigger("filterOptionsChanged"); }, 200); 

Что будет надеяться, оттянуть курок достаточно долго для браузера, чтобы перекрасить интерфейс (можно/нужно добавить немного значка загрузки в исходной функции, затем удалите его в таймаут). Вы также можете взглянуть на web workers, которые выглядят так, будто они довольно много потоков.

+0

Алекс, место на. Это революционно для меня, я не знал, что js зависает от пользовательского интерфейса, когда он интенсивно работает. Я вижу, что теперь Web Workers - это путь, но они не поддерживаются ниже ie10, и я работаю над проектом, на котором много пользователей на старых компьютерах. Тем не менее, ваше быстрое исправление делает кнопку тикания мгновенной и инициирует загрузочное сообщение, которое я хочу, в то время как более интенсивный материал работает. Прекрасно работает. Возможно, я могу придумать проверку браузера и направить код на веб-рабочего для более позднего и лучшего решения. –

+0

Если вы выполняете проверку браузера, обязательно проверяйте * возможности *, а не * версии *. 'typeof (Worker) ===" undefined "' и whatnot. Ура! –

+0

Word. Большое спасибо –

0

Попробуйте это,

CSS:

ul.tick-boxes button.active .tick-box::after { 
    content: "\e603"; 
    font-family: "custom-icons"; 
    color: #51425d; 
    top: 2px; 
    left: 2px; 
    font-size: 0.75rem; 
    position: absolute; 
} 

JS:

$("ul.tick-boxes button").click(function(event) { 
     event.preventDefault(); 
     $("ul.product-grid").addClass("loading"); 
     $(this).toggleClass("active").fadeIn(10, function() { 
      $theElement.trigger("filterOptionsChanged"); 
     }); 
    }); 

Использование обратного вызова, чтобы задержать запуск. Посмотрите, работает ли это для вас.

Смежные вопросы