Работа с `return false` при использовании` eval` в JavaScript - PullRequest
5 голосов
/ 04 октября 2011

Я имею дело с ситуацией, когда мне нужно привязать события jQuery к странице для обработки обновлений пользовательского интерфейса, которые генерируются с помощью JSF. Увы, JSF отстой и прикрепляет события onclick ко всему, что препятствует любой моей работе с jQuery.

Благодаря замечательным людям здесь, на SO, я нашел решение для этого:

смешивание моих событий нажатия jQuery с атрибутом onclick существующего объекта

Логика:

  • при загрузке страницы, захватите все атрибуты onclick и сохраните их в переменной.
  • привязать мои события jQuery
  • после моих собственных событий jQuery я могу eval исходный клик: eval(onclickValueVariable)

Это сработало во всех моих фиктивных тестах на onclick.

Но тогда на этой странице JSF не получилось. Проблема заключается в том, что все конец onclick заканчивается «return false», что приводит к этой ошибке:

return not in function

Например:

<div class="uglyJSFcreatedTag" onclick="console.log('hey');return false">

И jQuery, который его запустит:

var $jsfTag = $('.uglyJSFcreatedTag');
var cacheOnclick = $jsfTag.attr(onclick);
$jsfTag.removeAttr('onclick');

...bunch of logic here to decide if the inline onclick should fire and, if so...

eval(cacheOnclick)

Проблема в return false. Похоже, что ничего не может быть возвращено при увольнении eval.

Есть ли решение для этого? Я полагаю, что могу взять значение в виде строки и выполнить синтаксический анализ строки, чтобы удалить все возвращаемые значения false, а затем вызвать это из самого сценария. Но это звучит немного грязно. Есть ли более элегантное решение?

Если нет, то какие конкретные операторы JS мне нужно отфильтровать перед вызовом eval?

Ответы [ 2 ]

6 голосов
/ 04 октября 2011

Два варианта:

1. Используя ваш текущий подход, просто оберните строку onclick функцией перед тем, как ее проверить.Сохраните результат и вызовите его как функцию.Убедитесь, что вы вызываете его в соответствующем this контексте:

var f = eval("(function(){ "+cacheOnclick+"})");
f.call($jsfTag[0]);

Примечание: круглые скобки () вокруг объявления функции, обязательны в пределах eval.Это превращает объявление в выражение (синтаксически говоря), что делает его легальным в eval.

2. вместо захвата атрибута onclick , возьмитефактическая функция от самого элемента DOM.Кроме того, если вам не нужно делать что-то особенное с функцией обработчика jsf из вашего кода, я бы посоветовал вам просто добавить функцию JSF непосредственно в качестве обработчика щелчков jquery, а не вызывать ее явно из своего кода:

var $jsfTag = $('.uglyJSFcreatedTag');
$jsfTag.bind('click', $jsfTag[0].onclick);
$jsfTag.removeAttr('onclick');

Лично я бы пошел на подход № 2, но любой из них должен работать.


Обновление : Вот небольшое дополнительное объяснение для Варианта № 2:

var $jsfTag = $('.uglyJSFcreatedTag');

Это из вашего примера - мы используем jquery для извлечения набора, содержащего все элементы с именем класса 'uglyJSFcreatedTag'.

$jsfTag.bind('click', $jsfTag[0].onclick);

Извлекает первый элемент из набора ($jsfTag[0]) и получает свойство onclick этого объекта-элемента..onclick - это свойство javascript, которое содержит ссылку на скомпилированную функцию, сгенерированную браузером из строкового содержимого атрибута «onclick».Теперь, поскольку у нас есть функция-обработчик, мы можем связать ее непосредственно с событием щелчка jquery, используя функцию jquery bind() .

$jsfTag.removeAttr('onclick');

Наконец, мы просто удалим атрибут.Это нормально, потому что мы уже связали функцию с помощью jquery.Если мы не удалим его из старого клика, он будет вызван дважды.

Примечание: Возможно, вы заметили, что приведенный выше код работает только напервый элемент в выбранном наборе.Для очень вероятного случая, когда ваш набор содержит несколько элементов, вы захотите пройтись по набору и обрабатывать каждый элемент отдельно.Вот как вы это сделаете:

var $jsfTag = $('.uglyJSFcreatedTag');
$jsfTag.each( function(idx, element) {
    $(element).bind('click', element.onclick).removeAttr("onclick");
});

Если вы хотите пропустить обработчик jsf для определенных элементов, то вставьте логику в «каждый цикл», чтобы проверить это, и пропустите вызов для связывания соответствующим образом.


Если вы должны продолжать вызывать обработчик jsf из вашего обработчика кликов, то хотя бы подумайте об использовании element.onclick вместо $(element).attr('onclick').Последний требует eval, а первый - нет.

4 голосов
/ 04 октября 2011

Я думаю, что завернуть код в анонимную функцию и сразу вызвать его должно быть проще, чем отфильтровывать операторы возврата.

evalCode = "function() {" + evalCode + "}()";
...