Почему использование onClick () в HTML - плохая практика? - PullRequest
128 голосов
/ 03 мая 2011

Я много раз слышал, что использование событий JavaScript, таких как onClick(), в HTML - это плохая практика, потому что это плохо для семантики.Я хотел бы знать, каковы недостатки и как исправить следующий код?

<a href="#" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>

Ответы [ 9 ]

162 голосов
/ 03 мая 2011

Вы, вероятно, говорите о ненавязчивом Javascript , который выглядел бы так:

<a href="#" id="someLink">link</a>

с логикой в ​​центральном файле JavaScript, которая выглядит примерно так:

$('#someLink').click(function(){
    popup('/map/', 300, 300, 'map'); 
    return false;
});

Преимущества

  • поведение (Javascript) отделено от представления (HTML)
  • без смешения языков
  • вы используете фреймворк javascript, такой как jQuery, который может решить большинство кросс-браузерных проблем для вас
  • Вы можете добавить поведение ко многим элементам HTML одновременно без дублирования кода
41 голосов
/ 03 мая 2011

Если вы используете jQuery, то:

HTML:

 <a id="openMap" href="/map/">link</a>

JS:

$(document).ready(function() {
    $("#openMap").click(function(){
        popup('/map/', 300, 300, 'map');
        return false;
    });
});

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

Это также означает, что я могу обрабатывать общие всплывающие окна, переписав снова:

HTML:

 <a class="popup" href="/map/">link</a>

JS:

$(document).ready(function() {
    $(".popup").click(function(){
        popup($(this).attr("href"), 300, 300, 'map');
        return false;
    });
});

Это позволит вам добавить всплывающее окно к любой ссылке, просто назначив ей класс всплывающего окна.

Эта идея может быть расширена еще больше, например:

HTML:

 <a class="popup" data-width="300" data-height="300" href="/map/">link</a>

JS:

$(document).ready(function() {
    $(".popup").click(function(){
        popup($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');
        return false;
    });
});

Теперь я могу использовать один и тот же бит кода для большого количества всплывающих окон на всем моем сайте без необходимости писать множество материалов для кликов!Yay за возможность повторного использования!

Это также означает, что если позже я решу, что всплывающие окна являются плохой практикой (а они есть!) И что я хочу заменить их модальным окном в стиле лайтбокса, я могу изменить:

popup($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');

до

myAmazingModalWindow($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');

и все мои всплывающие окна на всем моем сайте теперь работают совершенно по-другому.Я мог бы даже определить функции, чтобы решить, что делать во всплывающем окне, или сохранить предпочтения пользователей, разрешать им или нет.С помощью встроенного onclick это требует огромных усилий по копированию и вставке.

20 голосов
/ 03 мая 2011

Это не хорошо по нескольким причинам:

  • он смешивает код и разметку
  • код, написанный таким образом, проходит через eval
  • и выполняется в глобальномscope

Самое простое было бы добавить атрибут name к вашему элементу <a>, тогда вы могли бы сделать:

document.myelement.onclick = function() {
    window.popup('/map/', 300, 300, 'map');
    return false;
};

, хотя современными лучшими практиками было быиспользуйте id вместо имени и используйте addEventListener() вместо onclick, поскольку это позволяет связывать несколько функций с одним событием.

19 голосов
/ 08 февраля 2014

С очень большими приложениями JavaScript программисты используют больше инкапсуляции кода, чтобы избежать загрязнения глобальной области видимости.И чтобы сделать функцию доступной для действия onClick в элементе HTML, она должна находиться в глобальной области видимости.

Возможно, вы видели файлы JS, которые выглядят следующим образом ...

(function(){
    ...[some code]
}());

Это выражения для немедленного вызова функций (IIFE), и любая функция, объявленная в них, будет существовать только внутри их внутренней области.

Если вы объявите function doSomething(){} внутри IIFE, а затем сделаете doSomething() действием onClick элемента на своей HTML-странице, вы получите ошибку.

Если, с другой стороны,вы создаете eventListener для этого элемента внутри этого IIFE и вызываете doSomething(), когда слушатель обнаруживает событие щелчка, вы хороши, потому что слушатель и doSomething() разделяют область действия IIFE.

Для небольших веб-приложений сминимальное количество кода, это не имеет значения.Но если вы стремитесь писать большие, поддерживаемые кодовые базы, то onclick="" - это привычка, которую следует избегать.

12 голосов
/ 03 мая 2011

Есть несколько причин:

  1. Я считаю, что это помогает поддерживать разметку, то есть HTML и клиентские скрипты. Например, jQuery позволяет легко добавлять обработчики событий программно.

  2. Пример, который вы приводите, будет разбит на любом пользовательском агенте, который не поддерживает javascript или у него отключен javascript. Концепция прогрессивного улучшения будет поощрять простую гиперссылку на /map/ для пользовательских агентов без javascript, а затем добавлять обработчик щелчков программно для пользовательских агентов, которые поддерживают javascript.

Например:

Markup:

<a id="example" href="/map/">link</a>

Javascript:

$(document).ready(function(){

    $("#example").click(function(){
        popup('/map/', 300, 300, 'map');
        return false;
    });

})
8 голосов
/ 03 мая 2011

Это новая парадигма под названием " Ненавязчивый JavaScript ". Нынешний «веб-стандарт» гласит, что необходимо отделить функциональность от презентации.

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

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

6 голосов
/ 03 мая 2011

Ваш вопрос вызовет дискуссию, я полагаю.Общая идея заключается в том, что хорошо разделять поведение и структуру.Кроме того, afaik, встроенный обработчик кликов должен быть eval приведенным, чтобы «стать» настоящей функцией javascript.И это довольно старомодно, хотя это довольно шаткий аргумент.Ах, хорошо, прочитайте немного об этом @quirksmode.org

5 голосов
/ 19 февраля 2019

Редакция

Ненавязчивый JavaScript подход был хорошим в PAST - особенно привязка обработчиков событий в HTML считалась плохой практикой (в основном потому, что onclick events run in the global scope and may cause unexpected error то, что упоминалось Минхуаном)

Однако ...

В настоящее время кажется, что этот подход немного устарел и нуждается в некотором обновлении.Если кто-то хочет стать профессиональным разработчиком внешнего интерфейса и писать большие и сложные приложения, ему нужно использовать такие фреймворки, как Angular, Vue.js и т. Д. Однако эти фреймворки обычно используют (или позволяют использовать) HTML-шаблоны где обработчики событий привязываются непосредственно к коду html-шаблона, и это очень удобно, понятно и эффективно - например, в угловом шаблоне обычно пишут:

<button (click)="someAction()">Click Me</button> 

В необработанном js / html эквивалентом этого будет

<button onclick="someAction()">Click Me</button>

Разница в том, что в raw js onclick событие запускается в глобальной области видимости - но платформы обеспечивают инкапсуляцию.

Так в чем же проблема?

Проблема в том, что начинающий программист, который всегда слышал, что html-onclick является плохим и кто всегда использует btn.addEventListener("onclick", ... ), хочет использовать какую-то инфраструктуру с шаблонами (addEventListener также имеет недостатков - если мы обновляем DOM в динамическом режимеЕсли использовать innerHTML= - что быстрее, чем appendChild тесты здесь - тогда мы теряем привязку обработчиков событий таким образом).Тогда он столкнется с чем-то вроде вредных привычек или неправильного подхода к использованию фреймворка - и он будет очень плохо использовать фреймворк - потому что он сосредоточится в основном на js-части, а не на шаблонной части (и будет производить неясные и сложные в обслуживаниикод).Чтобы изменить эти привычки, он потеряет много времени (и, вероятно, ему понадобится немного удачи и учителя).

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

Так что же делать?

Мы можем ОБНОВИТЬ ненавязчивый подход JavaScript и разрешить связывать обработчики событий (в конечном итоге с простыми параметрами) в html (но только связыватьобработчик - не вводить логику в клик, как в операционном вопросе).Так что по моему мнению в сыром js / html это должно быть разрешено

<button onclick="someAction(3)">Click Me</button>

или

function popup(num,str,event) {
   let re=new RegExp(str);  
   // ... 
   event.preventDefault();
   console.log("link was clicked");
}
<a href="https://example.com" onclick="popup(300,'map',event)">link</a>

Но приведенные ниже примеры НЕ ДОПУСКАЮТСЯ

<button onclick="console.log('xx'); someAction(); return true">Click Me</button>

<a href="#" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>

Реальность меняется, наша точка зрения тоже должна

2 голосов
/ 08 ноября 2018
  • события onclick запускаются в глобальной области и могут вызвать непредвиденную ошибку.
  • Добавление событий onclick ко многим элементам DOM снизит производительность и эффективность
    .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...