Лучший способ выполнить Javascript на якоре

Как правило, есть 3 способа (что я знаю) для выполнения javascript из тега <a/>:

1) Используйте onclick():

<a href="#" onclick="alert('hello'); return false">hello</a>

2) Непосредственно ссылка:

<a href="javascript:alert('hello')">hello</a>

3) Или приложите внешнее:

// In an onload event or similar
document.getElementById('hello').onclick = window.alert('Hello'); 
return false;
<a id="hello" href="#">hello</a>

Я действительно загружаю ссылку через AJAX, поэтому # 3 в основном отсутствует. Итак, лучше ли делать # 1 или # 2 или что-то совершенно другое? Кроме того, почему? Каковы подводные камни, о которых я должен знать?

Также следует отметить, что якорь действительно нигде не связан, поэтому href="#", я использую a, поэтому стили соответствуют, так как это все еще объект, который нужно щелкнуть, и кнопка не подходит в контексте.

Спасибо

Ответ 1

Если вы загружаете контент через ajax и должны подключать обработчики событий, у вас есть следующие варианты:

  • Поместите обработчик javascript в свой HTML с вашим вариантом 1) или 2). На мой взгляд, вариант 1) - это более чистый способ его определения, но я не думаю, что там есть разница между 1) или 2) - они оба делают по сути одно и то же. Я вообще не поклонник этой опции, потому что я считаю, что она имеет значение для сохранения разметки и кода.
  • После загрузки содержимого с помощью ajax вызовите некоторый локальный код, который найдет и подключит все ссылки. Это будет тот же самый код, который у вас был бы на вашей странице, и выполнить в DOMReady, если HTML был статическим HTML на вашей странице. Я бы использовал addEventListener (откат к attachEvent), чтобы подключиться таким образом, поскольку он более чисто позволяет нескольким слушателям для одного объекта.
  • Вызов некоторого кода после загрузки содержимого с помощью ajax, который находит все ссылки и подключает клики к некоторому родовому обработчику кликов, который затем может просматривать метаданные в ссылке и определять, что должно быть сделано на этом клике на основе метаданные. Например, эти метаданные могут быть атрибутами по нажатой ссылке.
  • При загрузке содержимого также загружайте код, который может найти каждую ссылку отдельно и подключить соответствующий обработчик событий для каждой ссылки так, как это было бы сделано, если контент просто загружался на обычной странице. Это соответствовало бы желанию отделить HTML от JS, поскольку JS найдет каждую подходящую ссылку и подключит обработчик событий для нее с помощью addEventListener или attachEvent.
  • Как работает jQuery .live(), подключите общий обработчик событий для необработанных кликов по ссылкам на уровне документа и отправьте каждый клик на основе некоторых метаданных в ссылке.
  • Запустите некоторый код, который использует реальную структуру, например jQuery .live(), а не создает собственные возможности.

Что я буду использовать, будет немного зависеть от обстоятельств.

Прежде всего, из ваших трех вариантов привязки обработчика событий я бы использовал новую опцию # 4. Я бы использовал addEventListener (возвращаясь к attachEvent для старых версий IE) вместо того, чтобы назначать onclick, потому что это более чисто разрешает для нескольких слушателей элемент. Если бы это был я, я бы использовал фреймворк (jQuery или YUI), который делает кросс-браузерную совместимость невидимой. Это позволяет полностью разделять HTML и JS (без встроенного JS-кода с HTML), который, как я думаю, желателен в любом проекте, включающем более одного человека, и просто кажется мне более чистым..

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

Если бы было много разных фрагментов HTML, которые я динамически загружал, и было бы более чистым, если бы они были "автономными" и поддерживаемыми отдельно, тогда я хотел бы одновременно загружать как HTML, так и соответствующий код, так что иметь вновь загруженный код, подключая к нему соответствующие ссылки.

Если общая автономная система не требовалась, потому что было загружено всего несколько фрагментов, и код для их обработки мог быть предварительно включен в страницу, тогда я, вероятно, просто сделаю вызов функции после HTML-фрагмент был загружен через ajax, чтобы привязать javascript к ссылкам в только что загруженном фрагменте. Это обеспечит полное разделение между HTML и JS, но будет довольно легко реализовать. Вы могли бы поместить какой-то ключевой объект в каждый фрагмент, который идентифицировал бы какую часть JS для вызова или мог бы использоваться в качестве параметра для передачи JS или JS, мог бы просто изучить фрагмент, чтобы узнать, какие объекты доступны и подключить к какие бы ни были.

Ответ 2

Современные браузеры поддерживают Политика безопасности контента или CSP. Это самый высокий уровень безопасности в Интернете и настоятельно рекомендуется, если вы можете применить его, потому что он полностью блокирует все атаки XSS.

То, как CSP делает это, отключает все векторы, в которых пользователь может вставлять Javascript на страницу - в ваш вопрос, который является как вариантами 1, так и 2 (особенно 1).

По этой причине наилучшей практикой всегда является опция 3, так как любая другая опция будет разорваться, если CSP включен.

Ответ 3

Я твердо убежден в том, что я отделяю javascript от разметки. Должно быть четкое различие, ИМХО, между тем, что предназначено для показа, и тем, что предназначено для выполнения. С учетом этого избегайте использования атрибута onclick и вложения javascript:* в атрибуте href.

Альтернативы?

  • Вы можете включать файлы библиотеки javascript, используя AJAX.
  • Вы можете настроить javascript для поиска изменений в DOM (т.е. если это "стандартная задача", заставьте привязку использовать имя класса CSS, которое можно использовать для привязки определенного механизма, когда он будет добавлен позже динамически. (jQuery делает отличная работа при этом с .delegate()))
  • Запустите ваши скрипты POST-AJAX. (Принесите новый контент, затем используйте javascript для [re] связывания функций), например:

function ajaxCallback(content){
  // add content to dom
  // search within newly added content for elements that need binding
}

Ответ 4

Номер 3 не "выйдет", если вы хотите загрузить через AJAX.

var link = document.createElement("a");
//Add attributes (href, text, etc...)
link.onclick = function () { //This has to be a function, not a string
    //Handle the click
    return false; //to prevent following the link
};
parent.appendChild(link); //Add it to the DOM