Подтвердить что ты не робот

JavaScript: добавление обработчика onClick без перезаписывания существующего

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

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

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 как эта точка).

4b9b3361

Ответ 1

Вам нужно создать закрытие, чтобы сохранить исходное значение 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 и Дуглас Крокфорд.

Ответ 2

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

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

Ответ 3

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

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

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".

Ответ 4

как установить 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]);

Ответ 5

С помощью 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.

Ответ 6

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

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);
}