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 как эта точка).
Ответы
Ответ 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);
}
Ответ 7
У меня были проблемы с перегрузкой простым способом - эта страница была отличным ресурсом
http://www.quirksmode.org/js/events_advanced.html