Регистрация событий JavaScript без использования jQuery - PullRequest
29 голосов
/ 19 июня 2010

Как правильно сделать что-то вроде следующего без использования jQuery.

   $(document).ready(function(){
      $("#someButton").click(function(){
        alert("Hello");
      });
   });

Спасибо.

Ответы [ 6 ]

35 голосов
/ 19 июня 2010

Самый простой способ:

// DOM Level 0 way
window.onload = function () {
  document.getElementById("someButton").onclick = function() {
    alert("Hello");
  };
};

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

Также обратите внимание, что событие onload не полностью эквивалентно событию ready в jQuery, onload будет запущено, когда все ресурсы страницы будут полностью загружены (изображения, подкадры и т. Д.), в то время как ready срабатывает, как только DOM был проанализирован.

Если вы хотите подключить несколько обработчиков событий, вы можете использовать DOM Level 2 Standard element.addEventListerner метод (или element.attachEvent для IE)

Простейшая абстракция для кросс-браузерного способа привязки событий:

function addEvent(el, eventType, handler) {
  if (el.addEventListener) { // DOM Level 2 browsers
    el.addEventListener(eventType, handler, false);
  } else if (el.attachEvent) { // IE <= 8
    el.attachEvent('on' + eventType, handler);
  } else { // ancient browsers
    el['on' + eventType] = handler;
  }
}

Тогда вы можете:

var button = document.getElementById("someButton");
addEvent(button, 'click', function () {
  alert("Hello");
});

addEvent(button, 'click', function () {
  alert("world!");
});

Имейте в виду также, что методы addEventListener и IE attachEvent имеют свои различия: когда вы присоединяете несколько обработчиков к событию с addEventListener, они будут выполняться в том же порядке,поскольку обработчики были связаны (FIFO), attachEvent будет запускать обработчики наоборотзаказ (LIFO).

Проверьте пример здесь .

8 голосов
/ 27 ноября 2015

TL; DR

В современном браузере:

<input type="button" id="someButton" value="Some Button">
<script>
document.getElementById("someButton").addEventListener("click", function() {
    alert("Hello");
}, false);
</script>

Обратите внимание, что скрипт после кнопки в HTML. Почему это имеет значение? Продолжайте читать.

document.getElementById("someButton").addEventListener("click", function() {
    snippet.log("Hello");
}, false);
<input type="button" id="someButton" value="Some Button">
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

О, хорошо, ты продолжал читать.

Есть три части:

  1. Когда подключать обработчик (часть, для которой используется код jQuery ready)

  2. Как найти элемент (ы) для подключения (часть, для которой используется код jQuery $("#someButton"))

  3. Как подключить обработчик (часть, для которой он используется click)

Когда подключать обработчик

При обработке событий непосредственно в элементе вы не можете подключить обработчик событий, пока элемент не существует. Имея дело с элементами, которые находятся в основном HTML страницы, вы знаете, что они существуют после того, как их HTML был проанализирован. Так, например:

<div>...</div>
<script>
    // Here, we know that that div exists
</script>

Поэтому, если у вас нет веских причин поступить иначе, поместите теги сценария для вашего кода JavaScript в конец документа, непосредственно перед закрывающим тегом </body>. Тогда вы знаете, что все вышеперечисленные элементы (включая document.body) существуют.

Если у вас нет другого выбора, кроме как поместить теги сценария в другое место (например, анти-шаблон, который помещает их в <head>), тогда вам придется прибегнуть к подключению обработчика событий, когда содержимое страницы было разобран. Стандартным является DOMContentLoaded, к которому вы подключаетесь document. К сожалению, IE8 и более ранние версии не поддерживают его, поэтому jQuery обеспечивает обратный вызов ready. Вы также можете использовать событие load для объекта window, но оно не срабатывает до тех пор, пока long после анализа элементов страницы не будет, потому что он ожидает загрузки всех внешних ресурсов (все изображения и т. д.) до стрельбы.

Как найти элемент (ы) для подключения

В вашем примере элемент имеет значение id, поэтому вы можете использовать document.getElementById для его получения; который возвращает ссылку на объект элемента, или null, если его нет с этим id.

Современные браузеры, а также IE8 поддерживают document.querySelector, который найдет первый элемент, соответствующий любому селектору CSS. Так, например, document.querySelector('div') находит первый div в документе, если он есть (null, если его нет). document.querySelector('div.foo table tr.bar') находит первый tr элемент с классом bar, который находится внутри table, который находится внутри div элемента с классом foo.

Современные браузеры (и IE8) также предоставляют document.querySelectorAll, что дает вам список (набор) всех элементов, соответствующих селектору CSS.

querySelector и querySelectorAll также доступны для элементов; когда вы используете их для элементов, они смотрят только на потомков этого элемента.

Существуют также различные другие функции, такие как getElementsByTagName (поддерживается почти повсеместно, даже в старых IE), getElementsByName (с использованием атрибута name; у меня есть понятия не имею, насколько широко поддерживается), getElementsByClassName (поиск по одному классу CSS; в IE8 и более ранних версиях его нет) и некоторых других.

Как подключить обработчик

Современные браузеры, включая IE9 и выше в стандартном режиме, поддерживают addEventListener. В IE8 и более ранних версиях вы должны использовать оригинальный Microsoft attachEvent (предшествующий addEventListener).

theElement.addEventListener("click", function() {
    // ...your handler code here
}, false);

// or

theElement.attachEvent("onclick", function() {
    // ...your handler code here
});

Обратите внимание, что addEventListener просто использует имя события ("click"), но attachEvent использует "on" плюс имя события ("onclick"). Также обратите внимание, что addEventListener имеет третий аргумент, который вы почти всегда хочу установить значение false. (В последних браузерах этот аргумент был необязательным, но это не всегда, поэтому, если вам может потребоваться поддержка старых, включите его.)

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

Элементы также предоставляют свойства, которым вы можете назначить функции, где имя свойства - on, за которым следует имя события, например onclick:

theElement.onclick = function() {
    // Your handler code
};

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

Итак, мы можем реализовать ваш код jQuery следующим образом:

<script>
document.getElementById("someButton").onclick = function() {
    alert("Hello");
};
</script>
</body>
</html>

(Обратите внимание, где находится этот тег.) Но это не очень хорошо с другими.

document.getElementById("someButton").onclick = function() {
    snippet.log("Hello");
};
<input type="button" id="someButton" value="Some Button">
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Или в современном браузере:

<script>
document.getElementById("someButton").addEventListener("click", function() {
    alert("Hello");
}, false);
</script>
</body>
</html>

document.getElementById("someButton").addEventListener("click", function() {
    snippet.log("Hello");
}, false);
<input type="button" id="someButton" value="Some Button">
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Или на IE8 и более ранних версиях:

<script>
document.getElementById("someButton").attachEvent("onclick", function() {
    alert("Hello");
});
</script>
</body>
</html>

document.getElementById("someButton").attachEvent("onclick", function() {
    snippet.log("Hello");
});
<input type="button" id="someButton" value="Some Button">
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

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

Мы можем использовать приемы из этого другого ответа , чтобы перебрать коллекцию, так как она будет подобной массиву объект (но не фактический массив).Скажем, мы хотим найти обработчик для всех div элементов с классом foo:

var list = document.querySelectorAll("div.foo");
Array.prototype.forEach.call(list, function(element) {
    element.addEventListener("click", handler, false);
});
function handler() {
    this.innerHTML = "You clicked me";
}

(Не беспокойтесь об этом this, я расскажу об этом в "Подробнееисследовать "ниже.)

var list = document.querySelectorAll("div.foo");
Array.prototype.forEach.call(list, function(element) {
    element.addEventListener("click", handler, false);
});
function handler() {
    this.innerHTML = "You clicked me";
}
<div class="foo">foo</div>
<div class="foo">foo</div>
<div class="foo">foo</div>
<div class="foo">foo</div>
<div class="bar">bar (no handler)</div>
<div class="bar">bar (no handler)</div>
<div class="bar">bar (no handler)</div>
<div class="bar">bar (no handler)</div>

Дополнительные сведения

Обработка событий - это не только получение события.Иногда обработчики событий иногда хотят сделать:

  1. Получить информацию о событии (например, если клавиша была нажата, какая клавиша?)

  2. Запрет действия по умолчанию для события, если оно есть (например, предотвращение по умолчанию в событии submit в форме останавливает его отправку)

  3. Остановить распространение (всплывающее) событие на элементы контейнера

  4. Ссылка на элемент, к которому подключено событие (чтобы мы могли использовать один и тот же обработчик для нескольких элементов)

# 4 легко: на обработчике, связанном с любым из механизмов, которые мы обсуждали выше, внутри обработчика, this будет ссылаться на элемент, к которому было подключено событие.(Это не относится к соединениям атрибутов HTML, например, <div onclick="handler()">, что является одной из многих причин не использовать их.) Если вы сделали что-то еще с this (что вы можете), вы также можете получить доступ кэлемент, к которому вы подключили событие через свойство currentTarget объекта события (подробнее ниже).

К сожалению, способ сделать это отличается в IE8 и более ранних версиях attachEvent и в браузерах, соответствующих стандартам.(addEventListener).Вот функция hookEvent (которую я изначально написал для этого другого ответа ), которая позволяет использовать стандартизированный способ даже в старом IE:

var hookEvent = (function() {
    var div;

    // The function we use on standard-compliant browsers
    function standardHookEvent(element, eventName, handler) {
        element.addEventListener(eventName, handler, false);
        return element;
    }

    // The function we use on browsers with the previous Microsoft-specific mechanism
    function oldIEHookEvent(element, eventName, handler) {
        element.attachEvent("on" + eventName, function(e) {
            e = e || window.event;
            e.preventDefault = oldIEPreventDefault;
            e.stopPropagation = oldIEStopPropagation;
            handler.call(element, e);
        });
        return element;
    }

    // Polyfill for preventDefault on old IE
    function oldIEPreventDefault() {
        this.returnValue = false;
    }

    // Polyfill for stopPropagation on old IE
    function oldIEStopPropagation() {
        this.cancelBubble = true;
    }

    // Return the appropriate function; we don't rely on document.body
    // here just in case someone wants to use this within the head
    div = document.createElement('div');
    if (div.addEventListener) {
        div = undefined;
        return standardHookEvent;
    }
    if (div.attachEvent) {
        div = undefined;
        return oldIEHookEvent;
    }
    throw "Neither modern event mechanism (addEventListener nor attachEvent) is supported by this browser.";
})();

Использование hookEvent мы можем сделать три вещи, перечисленные ранее, стандартным способом:

  1. Мы получаем объект события в качестве первого аргумента функции-обработчика, что означает, что мы можем использовать его currentTarget чтобы получить ссылку на элемент, к которому мы подключили событие, или target, чтобы получить ссылку на элемент, из которого произошло событие, и т. Д.

  2. Мы можем предотвратитьпо умолчанию, вызывая функцию preventDefault объекта события

  3. Мы можем остановить распространение, вызывая функцию stopPropagation объекта события

  4. Мы можем использоватьthis (или event.currentTarget) для ссылки на элемент, где мы перехватили событие

hookEvent не является всесторонней, поющей, все танцующей функцией подключения события. (Во-первых, я никогда не заботился о поддержке un перехвата событий с ним.) Это пример кода, в основном.

Справочный материал

  • Большая часть этого теперь покрыта спецификацией HTML5, что намного больше, чем HTML

  • Различные аспекты определены DOM; список спецификаций здесь , текущий DOM4

  • Mozilla Developer Network имеет огромный диапазон достаточно точных референсных материалов (в отличие от некоторых других мета-сайтов, которые часто имеют проблемы с точностью).

1 голос
/ 19 июня 2010

Этот ответ не так прост без jQuery, потому что есть два основных стиля (в зависимости от того, какой браузер вы используете) для подключения событий.Если вы не используете один из этих двух стилей, ваши события могут перезаписывать друг друга.Вот более простой / перезаписывающий стиль:

window.onload = function() {
    document.getElementById("someButton").onclick = function() {
        alert("Hello");
    }
}

Но если вы попытаетесь выполнить приведенное выше дважды, вы получите только одно предупреждение, потому что второй раз перезапишет первое.В качестве альтернативы вы можете выполнить некоторое обнаружение браузера / функции, а затем использовать определенные механизмы событий для определенных браузеров;для получения дополнительной информации об этом стиле проверьте QuirksMode.com:

http://www.quirksmode.org/js/events_advanced.html

1 голос
/ 19 июня 2010

попробуйте это:

<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Test clicks</title>


  <script type="text/javascript">
    function setClicks() {
      var element = document.getElementById('test');
      element.onclick = function() {
        alert('test');
      }
    }
  </script>
</head>

<body onload="setClicks();">
  <div id="test" name="test">
    test
  </div>


</body>

</html>
1 голос
/ 19 июня 2010

Как насчет этого?

document.getElementById('someButton').onclick = function () { alert('Hello');}

0 голосов
/ 20 июня 2010

Насколько я знаю, onLoad НЕ совпадает с On DOM Ready.

On Load ожидает загрузки всех ресурсов (изображений, других внешних файлов).в то время как в DOM Ready ожидает только рендеринг HTML и не ждет загрузки ресурсов.

Исправьте меня, если я ошибаюсь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...