Предисловие
Начать хочется, с казалось бы, элементарной вещи – концепции разделения представления логики того или иного скрипта(компонента) и его представления. Битрикс представляет возможность работать с шаблонами компонентов, не трогая их логичесую реализацию, и более того дает возможность «допилить» ее путем создания некоторых файлов типа «result_modifier.php». Казалось бы все элементарно, и большинство разработчиков пользуется этой замечательной вещью в отношении HTML и PHP. Бывают конечно исключения и в практике приходится встречать вызовы одного компонента в шаблоне другого, а в шаблоне второго вызов еще одного, а в шаблоне третьего еще двух компонентов, в шаблоне которых вызывается пятый но с разными входными параметрами (Типовое решение «Медицинских учреждений»). Согласитесь, если это не комплексный компонент, то работать с таким кодом, и дорабатывать его очень трудно и тяжело. Ситуация с JavaScript не настолько катастрофична, как в предыдущем примере, но на мой взгляд если уж разделять логику и представление – то быть последовательным до конца и включить в эту концепцию JavaScript в том числе.
От человеческой лени или незнания или каких-либо других причин приходится сталкиваться со следующим мнением «Я так всегда делал», «Это надежно», «Так делали мои деды и прадеды». В пору вспоминается анекдот: «В комнате муха долбиться в окно, желая вылететь наружу. С другой стороны к ней подлетает другая муха и говорит: «Ты чего долбишься? Вон же форточка открыта». На что первая ей отвечает: «Нет, мой отец бился, мой дед бился, мой прадед бился в это окно и я биться буду.».». Есть несколько причин не делать так, как ты делал когда-то, и в этой статье я постараюсь осветить некоторые из них.
Атрибуты oncklick, onchange, onmouseover и им подобные в HTML
Часто в чужом коде приходится встречаться с таким примером:
Обратим внимание на атрибут onclick. Вариантов содержимого может быть несколько. Возможен какой-то код после которого стоит return false, возможен вызов функции, которая всегда возвращает ложь:
Теперь рассмотрим почему так делать не нужно:
1. Концепция разделения программирования и представление информации. Битрикс дает замечательную возможность перенести весь свой код в файл script.js, который автоматом подключается и очень удбен для разработки. Мое мнение - HTML должен быть чистый, со вкраплениями PHP и если возможности самого языка JavaScript а тем более популярного Framework jQuery позволяют не добавлять в HTML ничего не нужного, то этим стоит пользоваться. Сегодня мы сделали так, через месяц по другому, еще через неделю пришлось изменить логику и что то уже не приходит, какие то данные изменились и надо везде править изменения.
2. Происходит элементарное затирание объекта MouseEvent, который передается всегда в любом событии. Таким образом передавая параметры в нашу фукцию getData(this,<?=id?> мы просто лишаем себя многих возможностей, в том числе тмены стандартного обработчика события, но о нем еще поговорим ниже. Вот пример, который показывает объект MouseEvent, который содержит всю информацию о нажатии, и поверьте там есть все и даже больше того чего нужно:
JavaScript
jQuery
Таким образом, если мы передадим любой параметр в фукцию, то затрем параметр по умолчанию, что не есть хорошо. Этого можно избежать если все свои данные, необходимые для обработки, вы передадите в атрибут класса, или добавите элементы в DOM документ которые будут содержать эти данные опять же в своих классах. Если вы используете HTML 5, то для этого теперь есть атрибут data-{название}=”значение”, при небольшом ухищрении этот тег будет работать и в старых IE. Вариантов передать данные в HTML масса. В последствии многие просто не хотят или ленятся эти данные получать и вытаскивать из структуры DOM. Что тоже никак не оправдывает такой подход. С одной стороны использование атрибутов событий в HTML дает нам небольшое преимущество в скорости и простоте, но это старый век, и так делать некрасиво, тем более что зачастую, сами того не подозревая, нам нужны возможности объекта MouseEvent.
3. О «return false». Вообще в парадигме программирования функция возвращает либо результат операций, либо результат того что операции были выполнены успешно, либо результат того, что они были выполнены с ошибками или вовсе не выполнены. Уж точно возвращение лжи не было придумано для того чтобы ссылка не отрабатывала по событию click. Тем более часто бывает нужно что-то вернуть из функции, а мы уже себе поставили ограничение, и наша функция должна возвращает только ложь, чтобы не сработал стандартный обработчик тега <a>. Некоторые идут дальше и не используют атрибут href (что не верно, так как при сбое в скриптах или отключенной поддержке скриптов пользователь никуда не попадет), либо затирают или удаляют атрибут href в самом скрипте, что тоже является не красивым и приводит к той же проблеме сбоя скрипта и пользователь никуда не попадет.
Вернемся к нашему объекту MouseEvent. А ведь в нем уже все есть. Для JavaScript не нужно ничего дописывать, так как вышеприведенных примерах мы и так переопределили обработчик события click. А вот для jQuery это делается следующим образом:
jQuery
Делается это в конце функции, чтобы если вдруг произошел сбой в работе скрипта пользователь всегда мог перейти по ссылке.
Методы click(), bind(), live()
Если у нас на страничке очень много однотипных ссылок и нам нужно обработать их событие onclick, то так делать категорически не нужно:
jQuery
Что здесь происходит? Во первых метод each() – нужен совсем для других целей, он необходим для обработки массива объектов jQuery в данном случае его применение губительно. Фактически мы для кажого тега <a> назначили отдельное событие, то есть у нас зарегестрировано 4 события onclick, которые делают одну и ту же вещь! Если у вас на странице информация не добавляется с помощью ajax, то необходимо использовать метод bind() который зарегестрирует одно событие для данной группы тегов:
jQuery
Если же информация на страницу подгружается технологией ajax, то используя метод bind() новые тэги или группы тегов не будут откликаться по вашему обработчику, для этого используется метод live():
jQuery
Теперь все элементы структуры DOM в том числе и вновь добавленные будут закреплены за данным обработчиком события.
Примечание: Будте аккуратны используя данные методы. В сарых IE они не работают при использовании jQuery версии ниже 1.4.2.
Самый надежный метод регестрирования события on() так как он не меняется в jQuery от версии к версии и на его основе создаются другие методы, он является как бы родителем:
jQuery
Использование jQuery
Часто я сталкиваюсь с высказываниями «Нужно чтобы все работало быстро, минимум запросов, оптимальное использование PHP». И часто вижу на сайтах, что сервер быстро сгенерировал страницы, выполнил запросы, а страница все еще не готова, потому что грузятся скрипты. По хорошему нужно было бы написать целый раздел на эту тему, а не подтему одной статьи, но когда я вижу следующий код, то понимаю, что человек не совсем понимает для чего он использует jQuery:
jQuery
При загрузке страницы jQuery находит все теги с классом «links». Далее ко всем этим ссылкам добаляется параметр ajax. Создается впечатление что пользователь нажмет на все эти ссылки разом. Пользователь всегда нажмет на одну ссылку, поэтому целесообразний использовать следующий код:
jQuery
Таким образом мы поменяем ссылку только тогда, когда это нужно а не все время и на каждой странице(если скрипт не попадет в кэш). Возможен вариант когда пользователь не будет нажимать эти ссылки вообще, тогда зачем их обрабатывать?
Бывает так, что в теле функции происходит много ненужных опреаций. N раз берется элемент документа:
jQuery
В переменную а всё кладется как положено, но в переменню b каждую итерацию кладутся одни и те же данные, но с огромными потерями производительности, то есть на каждый чих мы ищем в структуре документа теги с классом someClass. Имя возможность их сохранить мы все равно дергаем DOM (а если количество строк в документе 5000?). Необходимо выносить такие вещи из тела функции:
jQuery
или:
jQuery
Первый вариант отработает по загрузке и готовности структуры документа, второй вариант - функция будет вызвана сразу же как только она встретится. К сожалению второй вариант и возможность битрикса с подключением файла script.js не совместим, так как этот файл подключается методом AddHeadScript(), а это значит, что она будет вызвана в head, до построения дерева. Второй вариант предпочтителено размещать в конце документа.
Эпилог
На этом все. В данной статье я старался рассмотреть лишь возможность делать лучше, и это лишь мое мнение. Я так же не отрицаю вариантов, когда нужно использовать другие подходы, гланое чтобы их использование было аргумментированным и целесообразным. Часто я встречаю непонятный код в компонентах Битрикс, которых сами разработчики уходят от использования своего стандартного функционала, вохможно это как раз тот пример, когда лучше сделать по другому.
Начать хочется, с казалось бы, элементарной вещи – концепции разделения представления логики того или иного скрипта(компонента) и его представления. Битрикс представляет возможность работать с шаблонами компонентов, не трогая их логичесую реализацию, и более того дает возможность «допилить» ее путем создания некоторых файлов типа «result_modifier.php». Казалось бы все элементарно, и большинство разработчиков пользуется этой замечательной вещью в отношении HTML и PHP. Бывают конечно исключения и в практике приходится встречать вызовы одного компонента в шаблоне другого, а в шаблоне второго вызов еще одного, а в шаблоне третьего еще двух компонентов, в шаблоне которых вызывается пятый но с разными входными параметрами (Типовое решение «Медицинских учреждений»). Согласитесь, если это не комплексный компонент, то работать с таким кодом, и дорабатывать его очень трудно и тяжело. Ситуация с JavaScript не настолько катастрофична, как в предыдущем примере, но на мой взгляд если уж разделять логику и представление – то быть последовательным до конца и включить в эту концепцию JavaScript в том числе.
От человеческой лени или незнания или каких-либо других причин приходится сталкиваться со следующим мнением «Я так всегда делал», «Это надежно», «Так делали мои деды и прадеды». В пору вспоминается анекдот: «В комнате муха долбиться в окно, желая вылететь наружу. С другой стороны к ней подлетает другая муха и говорит: «Ты чего долбишься? Вон же форточка открыта». На что первая ей отвечает: «Нет, мой отец бился, мой дед бился, мой прадед бился в это окно и я биться буду.».». Есть несколько причин не делать так, как ты делал когда-то, и в этой статье я постараюсь осветить некоторые из них.
Атрибуты oncklick, onchange, onmouseover и им подобные в HTML
Часто в чужом коде приходится встречаться с таким примером:
<a href="/catalog/sect_1/file.php" class="product_<?=$ID?>" id="<?=$product_id?>" onc lick="return false;">Перейти</a> |
<a href="/catalog/sect_1/file.php" class="product_<?=$ID?>" id="<?=$product_id?>" onc lick="getData(this,<?=$ID?>) ">Перейти</a> |
Теперь рассмотрим почему так делать не нужно:
1. Концепция разделения программирования и представление информации. Битрикс дает замечательную возможность перенести весь свой код в файл script.js, который автоматом подключается и очень удбен для разработки. Мое мнение - HTML должен быть чистый, со вкраплениями PHP и если возможности самого языка JavaScript а тем более популярного Framework jQuery позволяют не добавлять в HTML ничего не нужного, то этим стоит пользоваться. Сегодня мы сделали так, через месяц по другому, еще через неделю пришлось изменить логику и что то уже не приходит, какие то данные изменились и надо везде править изменения.
2. Происходит элементарное затирание объекта MouseEvent, который передается всегда в любом событии. Таким образом передавая параметры в нашу фукцию getData(this,<?=id?> мы просто лишаем себя многих возможностей, в том числе тмены стандартного обработчика события, но о нем еще поговорим ниже. Вот пример, который показывает объект MouseEvent, который содержит всю информацию о нажатии, и поверьте там есть все и даже больше того чего нужно:
JavaScript
<a href="/catalog/sect_1/file.php" class="product_<?=$ID?>" id="id_product" onc lick="return false;">Перейти</a> <sc ript type="text/javascript"> function getData(event){ console.log(event); } var a = docu ment.getElementById('id_product'); a.addEventListener('click',getData); </script> |
jQuery
<a href="/catalog/sect_1/file.php" class="product_<?=$ID?>" id="id_product" onc lick="return false;">Перейти</a> <sc ript type="text/javascript"> $('#id_product').click(f unction(event){ console.log(event); }); </script> |
3. О «return false». Вообще в парадигме программирования функция возвращает либо результат операций, либо результат того что операции были выполнены успешно, либо результат того, что они были выполнены с ошибками или вовсе не выполнены. Уж точно возвращение лжи не было придумано для того чтобы ссылка не отрабатывала по событию click. Тем более часто бывает нужно что-то вернуть из функции, а мы уже себе поставили ограничение, и наша функция должна возвращает только ложь, чтобы не сработал стандартный обработчик тега <a>. Некоторые идут дальше и не используют атрибут href (что не верно, так как при сбое в скриптах или отключенной поддержке скриптов пользователь никуда не попадет), либо затирают или удаляют атрибут href в самом скрипте, что тоже является не красивым и приводит к той же проблеме сбоя скрипта и пользователь никуда не попадет.
Вернемся к нашему объекту MouseEvent. А ведь в нем уже все есть. Для JavaScript не нужно ничего дописывать, так как вышеприведенных примерах мы и так переопределили обработчик события click. А вот для jQuery это делается следующим образом:
jQuery
$('#id_product').click(f unction(event){ //код event.preventDefault(); }); |
Методы click(), bind(), live()
Если у нас на страничке очень много однотипных ссылок и нам нужно обработать их событие onclick, то так делать категорически не нужно:
jQuery
<a href="http://www.google.ru" class="links">Google</a> <a href="http://www.yandex.ru" class="links">Yandex</a> <a href="http://www.mail.ru" class="links">Mail</a> <a href="http://www.qip.ru" class="links">QIP</a> <sc ript type="text/javascript"> $('.links').each(f unction(){ $(this).click(f unction(event){ event.preventDefault(); }); }); </script> |
jQuery
<sc ript type="text/javascript"> $('.links').bind(f unction(event){ event.preventDefault(); }); </script> |
jQuery
<sc ript type="text/javascript"> $('.links').live(f unction(event){ event.preventDefault(); }); </script> |
Примечание: Будте аккуратны используя данные методы. В сарых IE они не работают при использовании jQuery версии ниже 1.4.2.
Самый надежный метод регестрирования события on() так как он не меняется в jQuery от версии к версии и на его основе создаются другие методы, он является как бы родителем:
jQuery
$('#id_product').on(‘click’,f unction(event){ //код event.preventDefault(); }); |
Использование jQuery
Часто я сталкиваюсь с высказываниями «Нужно чтобы все работало быстро, минимум запросов, оптимальное использование PHP». И часто вижу на сайтах, что сервер быстро сгенерировал страницы, выполнил запросы, а страница все еще не готова, потому что грузятся скрипты. По хорошему нужно было бы написать целый раздел на эту тему, а не подтему одной статьи, но когда я вижу следующий код, то понимаю, что человек не совсем понимает для чего он использует jQuery:
jQuery
<a href="http://www.google.ru" class="links">Google</a> <a href="http://www.yandex.ru" class="links">Yandex</a> <a href="http://www.mail.ru" class="links">Mail</a> <a href="http://www.qip.ru" class="links">QIP</a> <sc ript type="text/javascript"> $('.links').each(f unction(){ $(this).attr('href',$(this).attr('href')+'&ajax=Y'); }); </script> |
jQuery
<sc ript type="text/javascript"> $('.links').bind(f unction(){ $(this).attr('href',$(this).attr('href')+'&ajax=Y'); }); </script> |
Бывает так, что в теле функции происходит много ненужных опреаций. N раз берется элемент документа:
jQuery
<sc ript type="text/javascript"> $('.links').each(f unction(){ var a = $(this).attr('class')+'_show'; var b= $('.someClass').attr('class'); }); </script> |
jQuery
<sc ript type="text/javascript"> $(docu ment).ready(f unction(){ var b= $('.someClass').attr('class'); $('.links').each(f unction(){ var a = $(this).attr('class')+'_show'; }); }); </script> |
jQuery
<sc ript type="text/javascript"> (f unction(){ var b= $('.someClass').attr('class'); $('.links').each(f unction(){ var a = $(this).attr('class')+'_show'; }); })(); </script> |
Эпилог
На этом все. В данной статье я старался рассмотреть лишь возможность делать лучше, и это лишь мое мнение. Я так же не отрицаю вариантов, когда нужно использовать другие подходы, гланое чтобы их использование было аргумментированным и целесообразным. Часто я встречаю непонятный код в компонентах Битрикс, которых сами разработчики уходят от использования своего стандартного функционала, вохможно это как раз тот пример, когда лучше сделать по другому.