JavaScript: добавление обработчика onClick без перезаписи существующего - PullRequest
15 голосов
/ 21 мая 2009

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

Тривиальный подход может выглядеть примерно так:

function adaptLinks()
{
    var links = document.getElementsByTagName('a');
    for(i = 0; i != links.length; i++)
    {
        links[i].onclick = function (e)
        {
            <do some work>
            return true;
        }
    }
}

Но некоторые ссылки уже имеют обработчик onClick , который следует сохранить. Я попробовал следующее:

function adaptLinks()
{
    var links = document.getElementsByTagName('a');
    for(i = 0; i != links.length; i++)
    {
        var oldOnClick = links[i].onclick;
        links[i].onclick = function (e)
        {
            if(oldOnClick != null && !oldOnClick())
            {
                return false;
            }
            <do some work>
            return true;
        }
    }
}

Но это не работает, потому что oldOnClick оценивается только при вызове обработчика (он содержит значение ссылки last как этой точки).

Ответы [ 7 ]

19 голосов
/ 21 мая 2009

Не назначать обработчику событий напрямую: используйте модель подписки addEventListener / attachEvent (в которой также есть пары удаления!).

Хорошее введение здесь .

16 голосов
/ 21 мая 2009

Вам необходимо создать закрытие, чтобы сохранить исходное значение onclick для каждой ссылки:

<a href="#" onclick="alert('hi');return false;">Hi</a>
<a href="#" onclick="alert('there');return true;">There</a>
<script type="text/javascript">
function adaptLinks() {
    var links = document.getElementsByTagName('a');
    for (i = 0; i != links.length; i++) {
        links[i].onclick = (function () {
            var origOnClick = links[i].onclick;
            return function (e) {
                if (origOnClick != null && !origOnClick()) {
                    return false;
                }
                // do new onclick handling only if
                // original onclick returns true
                alert('some work');
                return true;
            }
        })();
    }
}
adaptLinks();
</script>

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

Подробнее о замыканиях в comp.lang.javascript FAQ и от Дуглас Крокфорд .

4 голосов
/ 21 мая 2009

Используйте обертку вокруг addEventListener (браузеры, поддерживающие DOM) или attachEvent (IE).

Обратите внимание, что если вы хотите сохранить значение в переменной без перезаписи старого значения, вы можете использовать замыкания .

function chain(oldFunc, newFunc) {
  if (oldFunc) {
    return function() {
      oldFunc.call(this, arguments);
      newFunc.call(this, arguments);
    }
  } else {
    return newFunc;
  }
}

obj.method = chain(obj.method, newMethod);

В Аспектно-ориентированном программировании , это известно как " advice ".

0 голосов
/ 08 января 2010

У меня были проблемы с перегрузкой простым способом - эта страница была отличным ресурсом http://www.quirksmode.org/js/events_advanced.html

0 голосов
/ 06 августа 2009

Эта функция должна использоваться (подход к слушателям событий):

function addEventListener(element, eventType, eventHandler, useCapture) {
    if (element.addEventListener) {
        element.addEventListener(eventType, eventHandler, useCapture);
        return true;
    } else if (element.attachEvent) {
        return element.attachEvent('on' + eventType, eventHandler);
    }
    element['on' + eventType] = eventHandler;
}

или вы можете сохранить еще немного кода, добавив эту функцию (если вам нужно добавить одного и того же слушателя событий для многих элементов):

function addClickListener(element) {
    addEventListener(element, 'click', clickHandler, false);
}
0 голосов
/ 21 мая 2009

Используя JQuery, работает следующий код:

function adaptLinks(table, sortableTable)
{
    $('a[href]').click(function (e)
    {
        if(!e.isDefaultPrevented())
        {
            <do some work>
        }
    });
}

Это требует использования дополнительной библиотеки, но позволяет избежать некоторых проблем, которые существуют с addEventListener / attachEvent (например, проблема последнего с , это , ссылки ).

Существует только один подводный камень: если оригинальный обработчик onClick назначен с использованием «обычного» JavaScript, строка

...
if(!e.isDefaultPrevented())
...

всегда будет принимать значение true , даже если исходный обработчик отменил событие, вернув false. Чтобы это исправить, оригинальный обработчик должен также использовать JQuery.

0 голосов
/ 21 мая 2009

как насчет настройки oldClick = links[i].onclick or an empty function. Вот так

var oldOnClick = links[i].onclick || function() { return true; };

links[i].onclick = function (e)
   {
       if (!oldOnClick())
           return false;
       //<do some work>
       return true;
   }

Или вы можете использовать attachEvent и addEventListener, как другие рекомендовали

function addEvent(obj, type, fn) {
        if (obj.addEventListener)
                obj.addEventListener(type, fn, false);
        else if (obj.attachEvent)
                obj.attachEvent('on' + type, function() { return fn.apply(obj, [window.event]);});
}

и используйте вот так

addEvent(links[i], 'click', [your function here]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...