onclick = "" против обработчика событий - PullRequest
32 голосов
/ 04 августа 2011

Если я хочу, чтобы функция выполнялась, я предпочитаю делать встроенные js:

<p id="element" onclick="doSomething();">Click me</p>

потому что его легче отлаживать.

Однако я слышу, как люди говорят, что не следует использовать inline js, и делают:

document.getElementById('element').onclick = doSomething;

Почему рекомендуется прослушивать события js?

Ответы [ 8 ]

39 голосов
/ 24 февраля 2014

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

Однако на самом деле существует более серьезная проблема. ИМО: каким-то неуловимым способом оценки встроенных обработчиков событий.

Как вы, возможно, знаете, содержимое атрибутов on* будет использоваться как body функции-обработчика событий. Но какими характеристиками обладает эта функция?

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

<form>
    <input name="foo" />
    <button type="button" onclick="console.log(foo); console.log(window.foo);">
        Click me
    </button>
    <div onclick="console.log(foo);">Click me as well!</div>
</form>

Нажатие button журналов

<input name="foo"></input>
undefined

в консоли. Тот факт, что window.foo равен undefined, говорит о том, что глобальной переменной foo нет. Так откуда берется переменная foo? Почему console.log(foo) регистрирует элемент ввода и не выдает ошибку ссылки?
Поскольку свойства элемента form находятся в области действия обработчика событий, а элемент form имеет свойство для каждого именованного элемента управления формы, который он содержит. Вы можете легко проверить это с помощью console.log(document.querySelector('form').foo).

Теперь, щелкнув элемент div, выдается ошибка ссылки:

ReferenceError: foo is not defined

Таким образом, очевидно, что элемент form находится только в области элементов управления формой, а не какой-либо потомок. Насколько это сбивает с толку?

Аналогично, свойства объекта document также находятся в области действия встроенных обработчиков событий, что может привести к некоторым неожиданным ошибкам (знаете ли вы, что document имеет свойство plugins?).

Как именно оцениваются встроенные обработчики событий, формализовано в спецификации HTML5 . Создайте цикл на шаге 10, в частности, где описано создание цепочки областей действия.


Заключение

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

Статьи на quirksmode.org очень хорошо объясняют различные способы привязки обработчиков событий и их (dis) преимущества.

13 голосов
/ 04 августа 2011

По сути, это связано с тем, что все держится отдельно. Так что держите HTML / CSS / JS отдельно. Это делает ваш HTML более аккуратным и, я думаю, легче перемещаться без него.

Тогда, когда / если вам нужно внести большие изменения, у вас будет достаточно места для того, чтобы все равно переместить встроенный JS во внешний файл ИЛИ, если вы хотите применить одну и ту же функцию к более чем одной кнопке, тогда кода будет меньше. И чем меньше кода, тем счастливее место

Если у вас есть файлы JS правильно и тщательно документированы, то навигация по ним со стороны постороннего лица становится eaiser

4 голосов
/ 04 августа 2011

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

Быстрый пример (я использую jQuery просто для демонстрационных целей).

<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>

Что если вдруг вы получите запрос на изменение всех ваших параграфов для выполнения другой функции?В вашем примере вам придется изменить все вручную в вашем HTML-коде.Однако, если вы решите отделить HTML от JavaScript, вы можете просто сделать это следующим образом.

<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>

$('.element').bind('click', doSomethingElse);

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

РЕДАКТИРОВАТЬ: Ниже приводится пример для моего комментария.

Project = {
    // All the variables/constants/objects that need to be globally accessible inside the Project object.

    init : function(){
        // Main entry point...
        this.MainMenu.init();

        // Rest of the code which should execute the moment Project is initiated.
    }
}

Project.MainMenu = {
    // All the variables/constants/objects that need to be accessible only to MainMenu.

    init : function(){ // Is run immediatelly by Project.init()
        // Event handlers relevant to the main menu are bound here

        // Rest of the initialization code
    }
}

Project.SlideShow = {
    // All the variables/constants/objects that need to be accessible only to SlideShow.

    init : function(){ // Is run only on pages that really require it.
        // Event handlers for the slideshow.
    }
}
3 голосов
/ 24 октября 2013

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

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

2 голосов
/ 01 ноября 2017

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

OP в его примере действительно показывает это разделение!В встроенном обработчике событий нет логики, а есть просто ссылка на функцию / вызов, которая будет выполняться при событии "click" ... сама логика может поддерживаться отдельно в другом месте.

Я лично предпочитаю такой подходиз-за логического обнаружения потока.Если я никогда раньше не видел приложения ... первое место, где я собираюсь начать свой обход кода, находится в DOM, и тут же станет ясно, какие обработчики событий находятся в игре, а какие функции обеспечивают логику дляобработчики.С использованием, скажем, подхода к обработке событий «JQuery.On», просто просматривая html, вы не представляете, какие обработчики действительно подключены и предоставляют функциональность.

Встроенные обработчики событий, которые просто предоставляют указатели на функции,просто связывая события и не пропуская логику в презентацию.

0 голосов
/ 27 февраля 2018

Помимо перспективы стандартов кодирования

Использование атрибутов:

<p id="element" onclick="doSomething();">Click me</p>

если вы добавите тот же атрибут снова (см. Ниже) - рассматривается последний.

<p id="element" onclick="doSomethingMore();">Click me</p>

Использование обработчика событий:

document.getElementById('element').onclick = doSomething;

и скажем, вы добавили строку ниже

document.getElementById('element').onclick = doSomethingMore; Вызываются оба обработчика.

0 голосов
/ 04 августа 2011

Я не знаю, и преимущество использования встроенного обработчика по сравнению с присоединением обработчика позже. По своему опыту я предпочитаю использовать встроенный метод, когда мне приходится иметь дело с динамическими элементами, например, если я хочу добавить обработчик для каждого изображения, и количество изображений изменяется в соответствии с другими данными (например, изображения в дБ). В этом случае использование inline позволяет мне добавлять обработчик к каждому изображению, в противном случае мне нужно пересчитать количество изображений в файле javascript для добавления и обработки к каждому изображению.

Конечно, когда вы можете использовать библиотеки, такие как jQuery, где вы можете легко получить список встроенных элементов, которые не нужны

0 голосов
/ 04 августа 2011

Вы можете сказать то же самое о CSS и включении встроенных стилей.Было бы легко не просматривать файл css, чтобы найти текущий класс / идентификатор или родительские / дочерние элементы, с которыми вы работаете.

Действительно ли лучше привязать щелчок, чтобы сказать 10 различных элементов в строке?Или только один обработчик событий, нацеленный на класс?Даже если вам не нужны 10 обработчиков щелчков, всегда лучше настроить код на удобство сопровождения и обновить его в будущем.

...