Сразу спешу сообщить вам, что я никоим образом не связан с автором предыдущей статьи. Однако, прочитав ее и увидев такой положительный отклик сообщества на статью, я тоже вдохновился и решил добавить немного своих наблюдений и знаний, к тому же это может послужить моей входной точкой в круги хабрасообщества.
Для затравки начнем с простого.
1. Пишите так, как вы говорите это вслух
Ваша задача перед другими программистами показать, что вы делаете, а не как вы это делаете.
Прежде чем написать очередную порцию кода, задумайтесь и проговорите вслух или про себя то, что вы собираетесь сделать. Например: «Нужно бы очистить этот элемент». Многие сразу, не задумываясь, лепят:
$(".info").html("")
потому что раньше использовали удобную фразу .innerHTML = ""
. Более же предпочтительный вариант:
$(".info").empty()
Эти же программисты часто очищают элемент перед тем, как поместить в него новую информацию:
$(".info").html("").html("<b>Ok</b>")
Но не забывайте – вы пишете на jQuery! А он заботится о вас, и .html()
сам очистит элемент перед вставкой нового значения.
Причем он сделает это более грамотно, нежели это делать через .innerHTML
. Дело в том, что внутри очищаемого элемента могут находиться такие элементы, на которые вы ранее повесили обработчики событий или привязали данные с помощью .data()
. jQuery почистит это и никакой утечки памяти не будет.
Кстати, иногда для того, чтобы убрать информацию, целесообразнее не просто очистить элемент, а удалить его вовсе:
$(".info").remove()
Далее…
Вряд ли при написании вот такого:
$("#history").css("display", "none")
$("#description").css("display", "none")
$("#category").css("display", "none")
$("#contact").css("display", "none")
вы проговаривали: «Удалить историю, удалить описание, удалить категории, удалить контакты». Скорее всего, вы сказали: «Удалить историю, описание, категории и контакты». Так напишите же это:
$("#history, #description, #category, #contact").hide()
и не забывайте, что jQuery любит вас, и что для скрытия элемента есть .hide()
, а для показа – .show()
.
2. mouseenter/mouseleave
VS mouseover/mouseout
Вы, наверное, замечали неприятность: иногда, когда вы вешаете на элемент пару событий mouseover/mouseout
для отображения всплывающей подсказки, происходит мелькание этой подсказки. А происходит это из-за того, что внутри элемента, на который вы навесили обработчики, находится другой элемент. При наведении на него курсора мышки браузер генерирует для вашего внешнего элемента событие mouseout
, а для внутреннего – mouseover
, после чего опять для внешнего – mouseover
, что и приводит к передергиванию.
Но jQuery любит нас и предлагает нам другую пару событий — mouseenter/mouseleave
, которые решают эту проблему следующим образом. Для переданных обработчиков делается некая обертка. В момент, когда курсор переходит на внутренний элемент, генерируется событие mouseout
для внешнего элемента. При этом jQuery не настолько наивен и не ведется на козни браузера. Скептическая функция-обертка проверяет свойство event.relatedTarget
– то, на что навели теперь курсор – и если оно находится внутри внешнего элемента, то не вызывает переданный вами обработчик mouseleave
. И никаких мельканий.
В довесок к этому, не забываем про функцию .hover(handlerIn, handlerOut)
, которая принимает два обработчика и навешивает их как mouseenter
и mouseleave
:
$(selector).hover(function() {
tooltip.show()
}, function() {
tolltip.hide()
}
3. .parent()
VS .closest()
Нередко натыкаюсь вот на такую конструкцию:
var person = $(".name").parent().parent().parent()
Понятно, что здесь представлена попытка добраться до важного родителя, у которого есть важная информация, или в котором находится другой нужный элемент. А что делать, если пока вы были в отпуске, ваш $(".name")
приютился в другом месте, но в рамках все того же person
? Многие умельцы циклически вызывают .parent()
до нужного элемента.
Более прошаренные знают, что есть .parentsUntil(selector)
, который вернет всех родителей до указанного (исключая его). Но все равно решение громоздко:
var person = $(".name").parentsUntil(".person").last().parent()
Но есть более наглядный способ:
var person = $(".name").closest(".person ")
Если вспомнить, что мы пишем код таким, каким бы мы выразили его словами, то указанный вариант больше подходит своей прозрачностью и лаконичностью.
4. $.ajax()
– лучше меньше, да лучше!
Все мы любим AJAX, особенно $.ajax()
. А насколько сильно любите его вы? В предыдущей статье другого автора приводились полезности работы с этим компонентом. Приведу парочку своих…
Я вряд ли совру, если скажу, что вы часто – если не всегда – обращаетесь по AJAX к одному и тому же файлу, передавая ему для разных действий разные команды. Вы ведь не плодите кучу файлов для коротких действий, надеюсь? Возможно даже, что вы всегда передаете какой-то параметр, который не меняется; и, возможно, вы всегда возвращаете только json. Давайте слегка упростим себе жизнь, ведь jQuery любит нас:
$.ajaxSetup({
dataType: "json",
url: "ajax.php",
data: {
user_id: userId
}
});
Теперь нам не придется каждый раз указывать эти параметры при запросах, достаточно только отличительных для данной операции:
$.ajax({
data: {
product_id: productId
},
success: function(json) {
console.log(json)
},
alert: "Загрузка товара..." // Для чего? См. ниже
})
и запросы не будут изобиловать повторами кода, которые мы так не любим. Обратите внимание, что параметры data
из $.ajaxSetup
и $.ajax
склеиваются, и серверу посылается их сумма (параметры из $.ajax
перезатирают одноименные из $.ajaxSetup
).
5. $.ajax()
– оповести пользователя
Так… А может теперь оповестим пользователя о своих подпольных делах и будем выдавать ему сообщения при AJAX-запросах? Уверен, вы об этом задумывались, но избегали в силу того, что надо часто писать одно и то же.
Для простоты примера будем выдавать сообщения таким образом:
<div id="popup" class="по-центру-жирным-красным"></div>
И свяжем его с нашими запросами:
$("#popup").ajaxSend(function(event, xhr, options) {
$(this).text(options.alert || "Подождите...").show()
}).ajaxStop(function() {
$(this).fadeOut("fast")
})
.ajaxSend()
вызывает обработчик каждый раз, когда происходит AJAX-запрос. Здесь мы выводим переданное (см. выше) сообщение или сообщение по умолчанию.
.ajaxStop()
вызывается в конце, после того, как все AJAX-запросы отработаны; т.е. если у вас параллельно обрабатывается несколько AJAX-запросов, то обработчик вызовется только один раз – после выполнения последнего запроса.
А если вы хотите выдавать каждый раз новое сообщение в отдельном попапе, то надо совсем немного изменить код:
$("body").ajaxSend(function(event, xhr, options) {
$('<div class="popup" />')
.appendTo(this)
.css({/* координаты */})
.text(options.alert || "Подождите...")
.delay(2000) // убрать через 2 сек
.fadeOut("fast", function() {
$(this).remove()
})
})
Вы также можете озаботиться о позиционировании попапа, добавив вычисление его будущих координат.
6. $.ajax() – оповести код
Давайте теперь посмотрим на наш попап из примера выше с другой стороны. Допустим, один человек является разработчиком некоторого сложного виджета, в котором отображается информация о текущих событиях на странице. А другой человек разрабатывает саму бизнес-логику и реализует AJAX-запросы. Очевидно, что потребность в виджете могла возникнуть уже после того, как было написано множество AJAX-запросов. Т.е. пока над проектом работает только один человек. Если бы мы любили наш код и своих будущих коллег так же, как любит нас jQuery, то мы бы предугадали потребность другого кода в оповещении его о завершении какого-нибудь нашего AJAX-действия. И сделали бы так:
$.ajax({
data: {
action: "search-name",
name: $("#name").val()
},
beforeSend: function() {
$(window).trigger("start.search")
},
complete: function() {
$(window).trigger("finish.search")
}
})
Теперь мы можем не беспокоиться, что кто-то в будущем ворвется в наши владения и попортит малину. Нам достаточно сообщить (в комментариях?), что все желающие могут подписаться, если им так будет угодно, на события start.search
и finish.search
:
$(window)
.bind("start.search", function() {
// Показать крутящийся прелоадер
})
.bind("finish.search", function() {
// Убрать крутящийся прелоадер
})
Ведь нам дана возможность создавать свои типы событий, генерировать их и подписываться на них. Все просто! :) jQuery любит нас.
Автор: LionMuzzle