Pull to refresh

Comments 109

UFO landed and left these words here
Спасибо за замечание. Хотя в оригинале у автора и стоит значок равенства, я думаю, все-таки, стоит поправить.
Действительно, отличные советы! Всё очень полезно и в одном месте.
искал решение по JQuery, зашел на Хабр, а тут такая красота =)
Шикаррно.
Распечатал cheat sheet, например.
Спасибо… много интересного. в Избранное
Ни у кого нет распечатываемой шпаргалки для 1.3.1 версии?
А советами уже давно пользуюсь, читал статью в оригинале.
может я чего-то не понимаю, но зачем её распечатывать?
я всегда юзал api.jquery.com/
достаточно удобно
Я, что-то не понял 25-й пункт: «сэкономить несколько символов, если использовать функцию»? Странно, мне кажется что если «не использовать что-то» то можно сэкономить на этом!..

Да и в пункт 21, я бы добавил такое маленькое дополнение «см. также AJAX-библиотеки в Google».
Теперь дошло! Подправьте 25-й пунктик, пожалуйста, на такое:
«Маленький прием, который поможет сэкономить несколько символов, если использовать сокращение функции $(document).ready.»

Сенькс! Когда переводишь, иногда несколько выпадаешь из контекста. Сейчас использую ваш вариант.
UFO landed and left these words here
Эммм… «неупорядоченный список»??? Вы хотели сказать «ненумерованный список» или «маркированный список»?
Ну, там суть именно в том, что неупорядоченный. Т.е. не отсортированный по какому-либо признаку. Суть, видимо, в том, чтобы проиллюстрировать, что мы «просто вставляем элементы», никак не заботясь о последовательности. Сам тоже отчасти думаю, что это лишнее определение, можно было бы назвать просто «список», к примеру.

В оригинале звучит как «unordered» — сложно подобрать правильный перевод в этом контексте, посему перевел дословно.
тег OL — ordered list, нумерованный список
тег UL — unordered list, ненумерованный список
Про .noconflict(): стоит упомянуть, что с момента употребления этой функции объект $ возвращается в первоначально определенное состояние. То есть, по-русски, если сначала вы загрузили Prototype, a потом jQuery, jQuery.noconflict() снова сделает объект $ прототиповской функцией. Это не всегда может быть удобно для дополнительного «навешивания» скриптов, полагающихся на jQuery в форме $. Посему (и не только поэтому), свои jQ-скрипты стоит писать следующим образом:
// начинаем файл нашего скрипта
(function($) // анонимная функция-обертка с параметром
{
$(".mystuff").do(things) // наши jQuery-выкрутасы, за состояние $ можно не бояться
}
)(jQuery) // и вот почему :)
// заканчиваем файл нашего скрипта

Первой и последней строчками мы оборачиваем наш скрипт в анонимную функцию, принимающую параметр $. В последней строке мы вызываем только что созданную функцию и в качестве этого параметра передаем объект jQuery. В итоге .noconflict() нам не страшен (его и можно, кстати, употребить в первой строчке нашего скрипта, перед объявлением функции). Заодно работа скрипта внутри анонимной функции, вызываемой немедленно после создания, не оставит после себя мусора в виде локальных переменных — если их объявлять с ключевым словом var, они исчезнут из памяти сразу после исчезновения контекста функции (то есть в простейших случаях сразу после окончания ее работы, в случаях замыканий при обработке событий — после снятия обработчиков событий). Практическая польза кажется небольшой и неочевидной, пока вы используете только jQuery, но стоит взяться за большой проект с несколькими библиотеками… сэкономите на Солпадеине, вобщем.
Еще момент: вчера всплывала статья про jQuery, хотел откомментить там, но хабр коммент сожрал.

Итак: кэшируя jQ-объект в переменную, именуйте ее с помощью $ в начале. То есть:

$a = $('a')


«Лишний» байт на самом деле сугубо повысит читаемость/разбираемось вашего кода для сторонних программистов (или вы гарантируете, что через год поможете модифицировать скрипт?). Особенно важно в обработчиках событий:

$('#myid').bind('click', function(){ // когда делаем обработчик события
var $this = $(this) // оборачиваем DOM-объект, на котором всплыло событие, в jQuery
})

Не понадобится обертка вокруг this — всегда можно удалить одну строчку. Но лично у меня уже стало паттерном, руки сами набирают, пока голова думает над деталями обработки события.

И еще. Бывает, глубоко в цепочке из многих .find() вдруг оказывается позарез нужна текущая jQuery-выборка в виде переменной. Понятное дело, не разорвав красивой цепочки, такую переменную не родишь ниоткуда. Заново повторять выборку ради своих действий тоже накладно. Для такого дела я когда-то написал простенький плагин: plugins.jquery.com/project/jquery_apply. Посреди цепочки можно вызвать .apply(function(){}), где внутри функции текущая jQuery-выборка доступна в форме this.
Дельный совет. Ну, на самом деле, автор и сообщает, что все нужно применять с умом ;)
За плагин спасибо.
Концентрация полезной информации — огромная, сам узнал правда только про расширяемые селекторы, но читать было очень приятно, спасибо. Одно несогласие:

23. Добавляйте класс «JS» в элемент «html»
— здесь будет явная проблема при открытии страницы, вы увидите много контента, а потом(в момент когда произойдет .ready() ) он спрячется. То есть пользователь увидит мерцающие блоки. К слову — подобный прием используется на главной странице mail.yandex.ru для скрытия боковых панелей — смотрится фигово, здесь лучше даже на таких монстров не ровняться.

зы: 24. return false; можно сократить до return !1;
Ну, 23 — это все же, как мне кажется, частный случай. Кому-то такое подходит, кому-то нет.

А вот 24 — что-то мне подсказывает, что «ох, не стоит же этого делать». Мало ли что он там не так сделает. «false» надежно, да и, на мой взгляд, читабельнее.
! — это логическая команда «отрицание», отрицание единицы по-булевски будет false, даже можно не проверять в других браузерах, все верно.
Ну, возможно. Про логическое отрицание я знаю, но вы же сами понимаете, реализации всегда неидеально. Впрочем, спорить не буду — надо проверить во всех браузерах, да и все.
23. Ну это смотря как сделать. Можно и css это всё выровнять. Например, как и на Я.Субботнике, когда Виталий Харисов рассказывал про CSS Framework. (теория (видео ч.1, видео ч.1) и практика (видео ч.1, видео ч.2)) Если у пользователя нет JS, то блок не скрываем. Вот простой пример:

Если фнкция не сработала, то у элемента html нет класса JS и в css пишем просто:
.block { display: block; }

Если сработала функция и элементу html был задан клас JS, то в css стилях очень просто написать:
.js .block { display: none; /*или visibility: hidden; */ }

Ну и конечно не забываем про наследование стилей.

А, вообще я больше склоняюсь к использованию id у элемента html. Изначально элементу html у меня выставляется свойство id="nojs" а уже потом JS-ом изменяется на id="js" И соответсветнно в css два стиля, для ситуации когда нет JS и когда JS есть.

#js .block { display: none; }

#nojs .block { display: block; }
вы видимо не поняли о чем речь — js срабатывает после того как уже загружен html, то есть рендеринг css будет на определенное время дольше, то что накидывается класс для body и пишутся исключения — и так ясно, проблема в том, что сначала срабатывает .block { display: block; }, а потом уже .js .block {display: none;}. Решение работает криво и через одно место, его нельзя рекомендовать.

менять id у элемента DOM-дерева через js — еще более неправлиный трюк, id для того и создан, чтобы однозначно инициализировать конкретный элемент, а не через него управлять отображением css. Представляю как двое-трое участвуют в разработке и один навешивает id для придания какогой-либо динамики через js, а другой для своих дизайнерских нужд эти id переопределят. Фу короче :)
id для того и создан, чтобы однозначно инициализировать конкретный элемент, а не через него управлять отображением css

Вы общались с Создателем?
Или кто ещё вам запретил использовать ID для отображения CSS?

Мне кажется, что техника #js .block — самое простое и эффективное решение проблемы обратной совместимости.

Решение работает криво и через одно место, его нельзя рекомендовать.

Что значит криво ичерез одно место?
Оно работает и проблем с задержками в рендеринге нет.
ferrari достаточно четко описал возможные проблемы при изменении id элемента. Что мешает использовать селекторы .js .block и .nojs .block? Классы для того и существуют, чтобы управлять отображением элементов.
Т.е. вы утверждаете, что html#js нельзя использовать, а html.js можно?

Вы не поверите, но ID тоже можно использовать для управления отображением элементов, и это, вроде как, никем не запрещено.
Я утверждаю, что нельзя скриптом менять html#nojs на html#js, о чем и говорил предыдущий оратор.
Omg, а так можно:

JS:

document.documentElement.id = 'js';

CSS:

.block {…}
#js .block {…}


?
Конечно. Но так вы лишаетесь стилей только для браузера без js, либо придется писать их в .block и переопределять в #js .block
Ну, естественно — сначала создаётся функционал простой, который так же просто описывается в CSS.
А потом его начинают JS-ить и пишут экстра-правила через #js.

Не вижу ничего странного, плохого или… эмм… влияющего на производительность. Описанный сценарий покрывает 90% применения такой обратной совместимости.

Исключение — когда компонент в принципе JS'ный и не имеет никакого вида с отключённым JS. В это случае — он просто не выводится на экран, а правила для него пишутся просто так.

Так в чём проблема с этим подходом, не могли бы вы резюмировать?
К тому же указывать атрибут «class» для <html> не валидно.

Нету этого атрибута, например в «XHTML Strict 1.0»:
<!ELEMENT html (head, body)>
<!ATTLIST html
  %i18n;
  id          ID             #IMPLIED
  xmlns       %URI;          #FIXED 'http://www.w3.org/1999/xhtml'
  >
UFO landed and left these words here
И вот ещё мелочь — в XHTML у элемента HTML нет атрибута class, есть только xmlns и id. Поэтому потенциально вы рискуете несовместимостью, но на практике наверное вряд ли.

Для кого-то это может иметь значение.
Я оперирую классами body.

Раз вы спрашиваете — проблема в том, что если вам нужно задать 10 правил для элемента, которые применяются только при отключенном js, то придется написать и еще 10 правил, возвращающих их в исходное состояние при включенном js. Вместо того чтобы просто отсечь их классом .nojs. Проблема небольшая, но иногда может доставить хлопот.

А вообще я высказался только против изменения id элемента (не присвоения безымянному, а именно изменения).
Вы хотите меня убедить что это правильный подход?
Я считаю что нет, даже если так делают уважаемые люди. Представьте, что в 1712 году Петербург переименовали бы в Москву, а Москву в Петербург, а в начале нашего века переименовали бы обратно. То есть вместо статуса изменили бы идентификатор.
Вы правда видите что-то общее, между атрибутом ID и названием города? :-O
У них одна суть — однозначная идентификация объекта. В отличие от классов и статусов, которые могут меняться, что мы и видим в нашем примере: обычный документ приобретает статус документа с js, и это влияет на его представление.
Ну и, гм, указанное решение хорошо не только уважаемостью людей, его использующих, но и тем, где это используется — проекты Яндекса создаются в большой команде (был такой аргумент выше) и все нагрузочные вопросы внимательно тестируются.
Объясните тогда, чем плох вариант с классом (кроме того, что его не используют в Яндексе)?
У элемента HTML нет атрибута class.
Ну хоть убейся )
Вадим, относись к жизни проще. Каждый вправе считать себя самым правым. Сторонние читатели уже поняли для себя какой метод лучше.
Да нет, я крепко сплю и аппетит хороший.
Просто из спортивного интереса пытался понять точку зрения товарища )
Упс пока писал комментарий, вы уже ответили это :-)
UFO landed and left these words here
А зачем текст серым делать?

Спасибо, полезный сборник.
Итак, зачем серый текст. Стандартные стили Хабра подходили не очень, так как нужно было выделить заголовки — здесь они играют чуть большую роль, чем обычно, поскольку озвучивают собственно советы. Кроме этого, я еще оставил выделенными кусочки кода. Как по мне, и думаю, многие согласятся, такое форматирование вполне себе очень читабельно.
Желание автора — закон, я лишь поинтересовался ;)
довольно фигово читабельно, честно говоря :)

но за перевод всё равно огромное спасибо, статья — клад!
Кстати, первый совет используется в ZendX_JQuery :)
Спасибо за перевод, действительно очень много полезной информации. Но хотелось бы дать несколько поправок/уточнений/пожеланий:

1. Загружайте фреймворк с Google Code

Я бы советовал с осторожностью отнестись к этой рекомендации. В большинстве случаев, да, все описанные плюсы будут иметь место. В меньшинстве — вы огребёте кучу проблем с юзерами, у которых по какой-то странной причине будет плохая связь с заграницей или конкретно с гуглом, с юзерами у которых из-за каких-то дебильных настроек дебильного софта не будут в принципе подгружаться данные с других доменов… Таких юзеров будут доли процента, но на хорошо посещаемом ресурсе это выльется в постоянную головную боль для поддержки.

3. Соединяйте все ваши скрипты и уменьшайте размер файла

Рекомендуется использовать Packer. Однако сами авторы jQuery начиная с версии 1.3 перестали выкладывать packed-версию, потому что потери времени на распаковку packed-скрипта заметно превышают выигрыш от уменьшения размера, плюс имеют проблемы с совместимостью. Подробности тут: blog.jquery.com/2009/01/21/jquery-131-released/. Их рекомендация — JSMin + gzip.

12. Научитесь назначать и делегировать события

В статье описывается версия 1.2.6. Начиная с версии 1.3 в jQuery появился специальный механизм для этого: docs.jquery.com/Events/live

Спасибо за замечания. Полностью согласен. В любом же случае, при использовании надо еще и головой думать :)
Насчет версии 1.3 — это да, действительно есть новый механизм и я думаю, можно будет его отдельно рассмотреть в отдельной статье (я уже даже встречал примеры с live в западных блогах, где все отлично описано).
Конкретно про live — я бы всё-таки попросил упомянуть в статье. Потому что это именно оно, а так народ, для которого это первый материал по сабжу, начнёт велосипеды изобретать.
Упомянуть стоит. Но, кстати, я тут подумал — а не разные ли все-таки это вещи? Цель, конечно, одна. Но суть в том, что в этой статье событие в итоге назначается один раз и уже в обработчике вся логика проверки дочерних элементов. В то время как live() занимается именно назначением событий, или не так? Я рассматриваю с точки зрения производительности.
Нет-нет, это как раз именно делегирование. Live именно цепляется один раз как глобальный обработчик, а потом при наступлении события смотрит, у кого оно произошло. Если селектор совпадает — вызывается соответствующий обработчик. То есть, один раз задав $('p').live('click', …), можно потом насоздавать сколько угодно параграфов, и все они будут отзываться на клик.

Там по ссылке-то всё написано:)
Ну я прочитал, но в коде-то не лазил, поэтому незнаю подробностей. Т.е. правильно я тогда понимаю, что новых обработчиков не назначается никаким элементам, а просто отслеживаются элементы по селектору и вызывается _только_ существующий обработчик?
Ок, всяко, спасибо за замечание. Как вы, наверняка, уже заметили, я внес поправки в статью и указал автора замечания.
UFO landed and left these words here
надо еще заметить что при такой google.load("jquery", "1.2.6") загрузке $(document).ready не будт работать
Куда уж «хабракатее». Считаю, что «содержание» всяко должна быть возможность прочитать до открытия статьи.
Достаточно само описание статьи показывать. По крайней мере, мне так кажется.
итак, статья имеет пару плохих советов.

В совете 6 корректный код должен выглядеть так:

var myList = $('.myList');
var myListItems = [];
for (i = 0; i < 1000; i++) {
myListItems.push('Это элемент списка № ' + i + '');
}
myList.html(myListItems.join(''));

В совете 24 правильно делать не так, а использовать e.preventDefault.

$('#id').click(function(e)
{
e.preventDefault();
// do actions
});
Может быть, но за всем не уследишь. По поводу совета 24 согласен, а вот насчет 6 — неуверен, надо проверять по производительности.
Проверьте :)

В большинстве браузеров, особенно в старых, использование массивов быстрее конкатенации при количестве подстрок от пяти.

Кстати, и запись так удобнее. Пример:

var html = [];
// тут много формирования HTML
html = html.concat(['В этой эпохе зафиксировано ', c, ' неликвидов.']);
// тут много формирования HTML
$('#info').html(html.join(''));
анписал автору статьи, на всякий :)
не в той раскладке, простите.

Хочу поделиться с хаброобществом своей статье о скорости селекторов и правильном их написании.

mabp.kiev.ua/2009/02/07/speed-up-jquery-selectors/

надеюсь будет полезно
Я капнул вам кармы, разместите просто запись у себя в блоге вида «Ссылка» на ваш материал.
Кажется прилегла ваша статейка от хабраэффекта (
хочу уточнить насчет вот этого:
$('#myImage').attr('src', 'image.jpg').load(function() {  
    alert('Картинка загружена');  
});


сработает ли alert() если картинка в кеше браузера и переключится моментально? не правильнее ли будет делать вот так:
$('#myImage').load(function() {  
    alert('Картинка загружена');  
}).attr('src', 'image.jpg');

Ваш код корректнее, однозначно.
>>2. Используйте «шпаргалку» (cheat sheet)
Мне очень сильно помогает шпаргалка сохраненная с visualjquery.com, может кому тоже поможет.
Вот тока её создатели что-то не хотят держать своё детище в актуальном состоянии.
По поводу анимации

Очень часто приходится анимировать свойства нескольких объектов сразу. В этом случае, для каждого события будет создан своя функция, которая будет выполняться независимо от других. Из-за этого обновление содержмиого страницы будет в несколько раз больше (чем, если бы выполнялась одна функция animate), и сильно упадет производительсноть такого решения.

Для решения этой проблемы можно использовать одну недокументированную возможность функции animate

//К, примеру, анимируем изменение height от 500 до 0
$("#first_element").animate(
    {height:0},
    {
        duration: "fast",
        step: function(curr, _this) {
			// функция вызывается каждый раз ДО изменения значения height у элемента
			// curr будет содержать текущее значение от 500 до 0
			
			// изменим значение height, округлим значение (по-умолчанию height будет дробным)
			// изменение curr не сохраняется, поэтому меняем _this.now
            _this.now = Math.floor(curr);
            
			// теперь получим относительное изменение высоты
			// т.е. X будет изменяться от 0 до 1
			var x = (500 - curr) / 500;
			
			// будем менять значение высоты у любого элемента
			// отдельный таймер не создается, поэтому все меняется при одном обновлении dom дерева
			$("#second_element")
				.css({height: 500 * x + "px", color: "rgb(" + (r + parseInt((0xFF - 0x00) * x)) + ", " + (g + parseInt((0xFF - 0x00) * x)) + ", " + (b + parseInt((0xFF - 0x00) * x)) + ")"});

        },
        complete: function()
        {
            // call oncomplete
        }
    }
);


Таким способом можно анимировать цвет, фон и т.д. без использования плагинов.
Штука интересная, интересно как бы получать и парсить rgb, а так же менять цвет из одного в другой таким вот методом.
все в одном месте, красиво и складно. да еще и с примерами. супер!
Ещё можно добавить к пункту "24. Возвращайте "false" для отмены поведения по-умолчанию":
Можно вместо
<a href="#" class="popup">Нажми меня, злодей!</a>
писать
<a href="javascript:void(0)" class="popup">Нажми меня, злодей!</a>
Эффект будет тот же и при этом можно не писать return false; в конце функции.
Рекомендую изучить непосредственно сам javascript. Мне кажется вы сможете это сделать, но jquery застилает вам глаза.

ЗЫ моя позиция: ничего не имею против использования фремвоков, но считаю что javascrit сам по себе дает куда большую свободу самовыражения.
Знаете как именно я в свое время понял JavaScript от и до? На примере изучения библиотечки Prototype, нашел внутри нее таааакой JavaScript, о каком не пишут ни в одном учебнике.
Есть. Но все же, очень хорошо на живом примере все рассматривать. Вот у меня в свое время Прототайп и был таким примером.
Может я немного забыл селекторы в jquery.
Но, думаю в пункте 24 вы пропустили точку (.)

$('.popup').click(function(){
// Код запуска popup'а
});
Спасибо, это самая лучшая статья по Jquery, которую я когда-либо видел!
UFO landed and left these words here
Большое Спасибо! Все советы очень полезные, подчеркнул для себя много нового!
Спасибо за статью! Понятно, доступно, для каждого! Есть, куда развиваться! :)
Only those users with full accounts are able to leave comments. Log in, please.