Переопределить поведение по умолчанию для объектов ссылки ('a') в Javascript

Я не знаю, возможно ли вообще то, чего я пытаюсь достичь. Я хотел бы переопределить поведение по умолчанию для всех объектов привязки (тег A) для данной HTML-страницы. Я знаю, что могу перебирать все элементы A и динамически добавлять вызов onclick к каждому из них из метода onload элемента body, но я ищу более абсолютное решение. Мне нужно, чтобы всем элементам A было назначено действие onclick, которое вызывает метод, передающий свойство элемента href в качестве аргумента, поэтому следующее:

<a href="http://domain.tld/page.html">

Динамически становится:

<a href="http://domain.tld/page.html" onclick="someMethodName('http://domain.tld/page.html'); return false;">

Как я уже сказал, идеальным способом сделать это было бы каким-то образом полностью переопределить класс Anchor при загрузке документа. Если это невозможно, я прибегаю к методу циклического прохождения всех A элементов (который я уже знаю, как это сделать).


person Community    schedule 19.11.2009    source источник
comment
Что ж, с делегированием событий им всем не нужно привязывать событие к ним. См., например, Live in jQuery. Или прочитайте о делегировании событий JavaScript.   -  person Nosredna    schedule 19.11.2009
comment
Обычно это нужно делать с HTML до того, как он попадет к клиенту. Если ваша страница сложная, вы можете столкнуться с большим количеством программ с делегированием событий.   -  person Ben    schedule 19.11.2009
comment
На самом деле, для события click я ожидаю меньше проблем с делегированием. Такие вещи, как отслеживание мыши, убьют тебя.   -  person Nosredna    schedule 19.11.2009
comment
И посмотрите это в отношении jQuery Live... zachleat.com/web/2009/05/08/   -  person Nosredna    schedule 19.11.2009


Ответы (6)


Если вы не хотите перебирать все элементы привязки, вы можете просто использовать делегирование события, например:

document.onclick = function (e) {
  e = e ||  window.event;
  var element = e.target || e.srcElement;

  if (element.tagName == 'A') {
    someFunction(element.href);
    return false; // prevent default action and stop event propagation
  }
};

Проверьте приведенный выше пример здесь.

person Community    schedule 19.11.2009
comment
Что, по вашему мнению, является преимуществом отсутствия итерации по якорным элементам? В некотором смысле это более навязчивый метод, поскольку он означает перенаправление всех кликов в документе! - person Benji XVI; 19.11.2009
comment
В вопросе явно упоминается, что не нужно повторять элементы привязки. - person Ben; 19.11.2009
comment
И это также более эффективно, когда вам не нужно сначала проходить элементы. - person jtbandes; 19.11.2009
comment
@Ben Конечно, но не дает уважительной причины: определенно ни в коем случае не информативно говорить, что установка свойства onclick каждого тега привязки не является «абсолютной». Просто интересно, была ли реальная причина задуматься? Кроме производительности, которая будет незначительной. - person Benji XVI; 19.11.2009
comment
@Benji XVI: одно из преимуществ этого метода заключается в том, что если дополнительные элементы привязки добавляются программно (например, контент, загруженный с помощью Ajax) после привязки этого события, он будет продолжать работать для этих новых привязок. - person Christian C. Salvadó; 19.11.2009
comment
Как вы сказали выше, Бен, «если ваша страница сложная, вы можете столкнуться с множеством проблем с делегированием событий». На мой взгляд, это, хотя и умный, на самом деле менее надежный метод, требует кросс-браузерного взлома и не имеет особых преимуществ. Это довольно синтаксически элегантно, но только для тривиального случая. - person Benji XVI; 19.11.2009
comment
@CMS Хороший вопрос. Если такое поведение требуется, это определенно может быть лучшим вариантом. - person Benji XVI; 19.11.2009
comment
Как обычно, ответ на вопрос, что лучше, зависит от того, что лучше. Если у вас много-много элементов, предназначенных для запуска по существу одного и того же кода, делегирование — это прекрасно. Если вы собираетесь перейти к оператору switch и иметь список различных действий для каждого идентификатора, это ужасно. - person Nosredna; 19.11.2009
comment
CMS: Спасибо, ваш метод работает отлично, он короткий и приятный, и, как вы сказали в одном из своих комментариев, он выполняет задачу применения ко всем элементам «А», а не только к тем, которые были на странице при ее первоначальном отображении - цель этого состояла в том, чтобы позволить новым тегам «A» из контента, загруженного через AJAX, продолжать работать. Отличная работа! - person boliva; 20.11.2009
comment
Действительно ли возврат false из прослушивателя событий предотвращает поведение по умолчанию? Где это задокументировано? - person Pasha Skender; 17.04.2016
comment
Этот ответ не работает, когда внутри тега ‹a› есть элементы DOM (например, изображение, что является очень распространенным случаем). Чтобы решить эту проблему, вам нужно заглянуть внутрь поля e.path и найти nodeName==='A' в предках. - person steph643; 04.02.2018
comment
Это решение сработало для меня. Однако то же самое с addEventListener с useCapture, установленным на true, не работает. Интересно, есть ли у кого-нибудь рабочее решение с addEventListener. - person Mikaël Mayer; 22.12.2018

Использование jQuery:

$(function() {
    $("a").click(function() {
        return someMethodName($(this).attr('href'));
    });
});

function someMethodName(href)
{
    console.log(href);
    return false;
}
person Community    schedule 19.11.2009

window.onload = function() {
    var anchorElements = document.getElementsByTagName('a');
    for (var i in anchorElements)
        anchorElements[i].onclick = function() {
            alert(this.href);
            return false;
        }
}

Это примерно самый простой способ сделать это. Оберните <script type="text/javascript">...</script> в заголовок документа, и он будет работать при загрузке страницы.

person Community    schedule 19.11.2009

Невозможно переопределить все элементы привязки по событию onlick. Вы можете добавить щелчок в тело документа и иметь логику, чтобы увидеть, распространяется ли даже от элемента привязки, и выполнить событие в этом случае, но это решение может вызвать проблемы, если ваша страница сложна и не распространяется клики в некоторых случаях.

Я бы придерживался решения getElementsByTagName, если это возможно.

person Community    schedule 19.11.2009

Аналогично ответу Бенджи XVI, но с использованием querySelectorAll, например, внутри контейнера div с классом «контейнер» и с использованием es6.

const $elems = document.querySelectorAll('.container a')
var elems = Array.from($elems)
elems.map(a => {
  a.onclick = (e) => {
    e.preventDefault()
    window.alert('Clicking external links is disabled')
  }
})
person Community    schedule 01.02.2018

Решение CMS является лучшим решением. Обязательно обратите внимание, что вы можете повысить производительность, если вы ссылаетесь на функцию или проверку, которую необходимо запустить, из строки, хранящейся в наборе свойств прототипа для базовой привязки/элемента или декларативно для привязки/элемента. Используя это свойство, функция, которую вы хотите вызвать, может быть найдена и вызвана из одной ветки решения, в отличие от написания новой ветки решения для каждой возможности. Если вы нарушаете или используете оператор case с более чем одним или двумя случаями, вы должны начать обдумывать это, сегодня может быть хороший день, чтобы определить инверсию управления и стиль кодирования внедрения.

Опять же, не используйте case, если вам нужно обработать несколько событий. Вместо этого используйте строковую композицию для создания пути к функции, которую необходимо вызвать. Это требует добавления прототипа к вашим элементам "A", которые определяют значение по умолчанию и составляющую строку. Атрибут данных элемента должен иметь возможность переопределять значение по умолчанию. По сути, мы просто хотим, чтобы сообщение и действие проходили по умолчанию и изменялись декларативно в разметке. Указанное действие должно быть где-то опубликовано как API или другая доступная библиотечная функция и должно быть доступно для вызова с помощью lib['funName']. Просто дайте ему атрибут, не беспокойтесь об имени или идентификаторе. Прототип и атрибут будут полезны для устранения дребезга, потому что вам придется устранять дребезг.

Есть несколько парней, работающих над клиентскими маршрутизаторами, которые пытаются усовершенствовать это.

person Community    schedule 02.04.2017