Динамическое создание обработчиков событий
Вчера столкнулся с необходимостью в зависимости от действий пользователя менять реакцию некоторых элементов страницы на разные события (в частности - onClick). Выяснилось, что простое присвоение в данное свойство не дает желаемых результатов. После некоторых раздумий и консультаций с коллегами решение было найдено.
Все дело в том, что есть два разных способа установки обработчиков событий, предназначенные для разных браузеров.
-
var Tag = document.getElementById('photo_larr');
-
if(Tag.addEventListener) {
-
if (num > 1) {
-
Tag.addEventListener('click', function() {show_popup_photo(num - 1);}, true);
-
}
-
else {
-
Tag.removeEventListener('click', function() {}, true);
-
}
-
} // Firefox или Opera
-
else {
-
if (num > 1) {
-
Tag.attachEvent('onclick', function() {show_popup_photo((num - 1));});
-
}
-
else {
-
Tag.detachEvent('onclick');
-
}
-
} // MSIE
Также вместо того, чтобы создавать функцию, можно указать имя уже существующей. Правда, в этом случае надо внимательно отнестись к ее параметрам.
В случае Firefox и Opera создаваемой функции можно давать имя. Это позволит прицепить в качестве обработчиков несколько действий.
Примечание: функция show_popup_photo(), переменная num и объект photo_larr в данном случае не имеют значения - на их месте может быть все, что угодно. Целью было просто создать некий пример использования определенных функций.


March 21st, 2007 at 09:45 Quote
ага, еще месяца два назад разбирался с этим, какраз и на описанные грабли ступал :)
March 21st, 2007 at 09:49 Quote
я уже несколько раз с этим разбирался. каждый раз успешно забывал, к чему привели разбирательства :). сейчас вот решил, наконец, записать.
March 21st, 2007 at 13:11 Quote
Есть более универсальный способ.
Изначально на этот photo_larr вешается в качетве обработчика функция назовём её photo_larr_OnClick()
потом когда нужно изменить реакцию делаем
eval('function photo_larr_OnClick(){alert("ПРЕВЕД!");}');
Таким образом мы глобально замещаем одну реализацию другой, причём всё в рамках стандарта javaScript безо всяких там обыгрываний DOM
March 21st, 2007 at 13:18 Quote
я испытываю большую неприязнь к
eval()и стараюсь нигде и никогда его не использовать. если надо, могу пояснить почему.March 21st, 2007 at 16:48 Quote
Поясни если не сложно
Кстати, опять-таки если не нравится eval можно использовать такой код
function someFunction1(){alert('someFunction1');}
function someFunction2(){alert('someFunction2');}
var photo_larr_OnClick_PROXY = someFunction1;
function photo_larr_OnClick(){photo_larr_OnClick_PROXY();}
И соответственно когда её надо изменить можно позвать
photo_larr_OnClick_PROXY = someFunction2;
March 21st, 2007 at 17:00 Quote
сначала по поводу приведенного варианта. он очень занятный. только понял я его со второго раза :). в общем-то, он тоже вполне жизнеспособен.
а про
eval()- это, в общем, большая дырка. изначально это у меня пошло от PHP и Perl, где он медленный и может привести к различным проблемам с security. да и всегда можно обойтись без него.в JavaScript он, в принципе, также может привести к проблемам. поэтому я не использую его вообще. просто перестраховка.
March 21st, 2007 at 17:10 Quote
По поводу eval в JavaScript - если это работает на клиенте то в принципе дырок нет, тем более если ты знаешь что за строчку ты передаешь в eval
На самом деле eval бывает очень полезен. Он, к примеру, используется как основная фича в JSON
Иногда при помощи eval можно сделать очень элегантные вещи. Допустим есть некоторая операция getSomeValue() которая может выполняться долго но результат её выполнения можно "закэшировать".
классический способ:
var getSomeValue_Cahce = 0;
function getSomeValue()
{
if(getSomeValue_Cahce==0)
getSomeValue_Cahce = getSomeValue_Actual();
return getSomeValue_Cahce;
}
использование eval()
function getSomeValue()
{ var n=getSomeValue_Actual();
eval('function getSomeValue(){return ' + n + ';}')
return n;
}
March 21st, 2007 at 17:21 Quote
вполне возможно. но все равно
eval()вызывает у меня неприязнь. и я не очень понимаю, чем второе решение элегантнее первого. оно несколько более сложно для понимания, как минимум. да и сработает чуть медленнее, по-моему. понятно, что ты просто оверрайднеш функцию сразу после кеширования. но как-то это некрасиво. не стыкуется с моим представлением о культуре программирования :) (ничего личного, если что).March 21st, 2007 at 17:48 Quote
Второе решение несколько замедляет ПЕРВЫЙ вызов но ускоряет последующие за счёт того что экономим на IF
Если вызов getSomeValue частый то общая экономия заметна. К тому-же избавляемся от глобальной переменной
Вообще в моей практике я достаточно часто использую eval чтобы генерировать некоторый код (причём бывает достаточно сложный) на лету.
Другое применение eval находит например для обыгрывания пользовательского интерфейса. К примеру есть таблица в которой надо отобразить записи, причём записи получаются с сервера (используем AJAX). Тогда например достаточно изящный способ - в заголовке таблицы доп-аттрибутами у ячейки я указываю выражение на JavaScript для форматирования. Например
[TD formatString="item.FirstName + ' ' + item.LastName + ' ' + item.MiddleName"]ФИО[/TD]
[TD formatString="item.Bithday"]День рождения[/TD]
Тогда при заполнении я использую универсальную функцию
function getTextForCell(item, formatString){return eval(formatString);}
March 21st, 2007 at 17:54 Quote
отчасти согласен. но я очень против eval'а полученных данных. это потенциально несекьюрно. конечно, если это только для вывода, тогда ничего. но если потом данные в каком-то виде снова идут на сервер - это нехорошо.
в общем, предлагаю сойтись на том, что eval() надо использовать аккуратно :)
P.S. как я уже говорил в самом начале, все мои претензии к eval() связаны с тем, что я трепетно отношусь к security.
March 21st, 2007 at 18:01 Quote
}}в общем, предлагаю сойтись на том, что eval() надо использовать аккуратно :)
Естественно :) Как любит говорить мой коллега про некоторые "фичи":
Фича "какая-то фича" это острая бритва при прмощи которой при неправильном обращении можно отрезать себе яй#а
}}как я уже говорил в самом начале, все мои претензии к eval() связаны с тем, что я трепетно отношусь к security.
Это и понятно :) Я вот в своё время даже экзамены сдавал http://www.microsoft.com/learning/exams/70-340.mspx