JavaScript Click Events — зачем мне два addEventListener?

Я изо всех сил стараюсь научиться ненавязчивому JavaScript. Приведенный ниже код является попыткой изменить существующий практический пример с помощью функции getArrays, вызываемой из тега HTML. Это единственная версия, с которой я мог работать. Хотя хорошо, что это работает, я чувствую, что могут быть некоторые ненужные части, и я не совсем понимаю, зачем мне нужна последняя строка кода (что-то новое для addEventListener). Я работал над справочным примером Mozilla DOM и уже знаю, как это сделать в jQuery. Спасибо!

JavaScript:

        <script>

        function getArrays() {
            var ddlValArray = new Array();
            var ddlTextArray = new Array();
            var ddl = document.getElementById("ddlFlavors");

            for (i=0; i<ddl.options.length; i++) {
                ddlValArray[i] = ddl.options[i].value;
                ddlTextArray[i] = ddl.options[i].text;
                alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
            }
        }

        function showArrays() {
            var link = document.getElementById("clickHandler");
            link.addEventListener("click", getArrays, false);   
        }

        document.addEventListener("DOMContentLoaded", showArrays, false);


    </script>

HTML

Select Flavor: 
<select id='ddlFlavors'>
<option value="1">Vanilla</option>
<option value="2">Chocolate</option>
<option value="3">Strawberry</option>
<option value="4">Neopolitan</option>
</select>

<br/><br/>
<a id="clickHandler" href="#">Show Flavors</a>

person Dave Hubbard    schedule 20.12.2012    source источник


Ответы (3)


Нет, если вы правильно структурируете свой HTML/JS.

Переместите тег script в нижнюю часть тела непосредственно перед тегом </body>, и вам больше не нужно ждать события DOMContentLoaded. HTML-код над ним будет проанализирован до выполнения JS.

Это МОЖЕТ вызвать другие предостережения, но для вашего примера это сработает.

<body>
Select Flavor:
<select id='ddlFlavors'>
    <option value="1">Vanilla</option>
    <option value="2">Chocolate</option>
    <option value="3">Strawberry</option>
    <option value="4">Neopolitan</option>
</select>
<br/><br/>
<a id="clickHandler" href="#">Show Flavors</a>
<script>
        function getArrays() {
            var ddlValArray = new Array();
            var ddlTextArray = new Array();
            var ddl = document.getElementById("ddlFlavors");
            for (i=0; i<ddl.options.length; i++) {
                ddlValArray[i] = ddl.options[i].value;
                ddlTextArray[i] = ddl.options[i].text;
                alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
            }
        }
        function showArrays() {
            var link = document.getElementById("clickHandler");
            link.addEventListener("click", getArrays, false);   
        }
        showArrays();
    </script>
</body>

Есть много других преимуществ размещения скриптов внизу. Подробнее о них читайте здесь.

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

person rlemon    schedule 20.12.2012
comment
Хотя этот ответ предлагает альтернативу подходу, который использует OP, на самом деле он не отвечает на вопрос зачем мне нужен addEventListener? Конечно, в этом случае нет настоящего нужны прослушиватели событий, но они очень мощные и в современном мире (ajax динамически добавляющий контент) абсолютно незаменимы - person Elias Van Ootegem; 21.12.2012
comment
Ага, да, просто нужно больше читать между строк. Я не рисую полную картину того, что происходит, но я намекаю на это. Тоже вопрос был зачем мне два, один правдоподобный ответ вам не нужен. - person rlemon; 21.12.2012
comment
Попался. В этом есть смысл. Спасибо! - person Dave Hubbard; 21.12.2012

Прослушиватели событий критически важны для JS. Каждый раз, когда пользователь взаимодействует с вашей страницей, вам нужно уловить это событие и отреагировать на него.
Конечно, в этом фрагменте ваши функции предполагают, что в DOM есть элемент с заданным идентификатором, готовый, установленный и ожидающий. Это может быть не так, поэтому вам нужно подождать, пока JS не получит OK (событие DOMReady).

Это всего лишь один очень простой пример того, почему можно использовать addEventListener. Но, по моему мнению, прослушиватели событий действительно проявляют себя, когда вы начинаете использовать вызовы Ajax для добавления нового контента на свою страницу по мере продвижения:
Предположим, что DOM готов, но некоторые элементы могут или не могут быть запрошены позже. (в зависимости от ввода пользователя). В jQuery вы бы использовали такие вещи:

$('#foo').on('click',functionRef);

Это не требует, чтобы элемент foo был доступен при запуске этого кода, но как только элемент будет добавлен в dom, события щелчка будут обрабатываться по вашему желанию.
В не-jQ вы будете использовать для этого addEventListener. Из-за модели событий (см. quirksmode для получения подробной информации о распространении и всплытии) прослушиватель не должен быть прикреплен к элементу напрямую:

document.body.addEventListener('click',function(e)
{
    if ((e.target || e.srcElemet).id === 'foo')
    {
        //function that deals with clicks on foo element
    }
},false);//last param is for bubbling/propagating events

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

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

document.body.addEventListener('click',function(e)
{
    e = e || window.event;
    var elem = e.target || e.srcElement;
    switch (true)
    {
        case elem.id === 'foo':
            //either code here or:
            return fooCallback.apply(elem,[e]);//use another function as though it were the handler
        case elem.id.className.match(/\bsomeClass\b/):
            return someClassCallback.apply(elem,[e]);//~= jQuery's $('.someClass').on('click',function);
         case elem.type === 'text':
             //and so on
    }
},false);

Довольно мощная штука. Есть, конечно, и многое другое, и минусы тоже есть (в основном X-браузеры), но основные плюсы:

  1. Обработка событий для элементов, которые динамически добавляются/удаляются
  2. Единый прослушиватель событий, который обрабатывает все события для всех элементов, делает ваш код более эффективным, иногда намного повышая производительность. вот хороший пример того, когда делегирование в порядке, к сожалению, это также показывает те трудности, которые приносит разработка X-браузера на вечеринку...
person Elias Van Ootegem    schedule 20.12.2012

Эта строка кода: document.addEventListener("DOMContentLoaded", showArrays, false); гарантирует, что ваша функция showArrays() не начнет выполняться до того, как DOM будет готов. Другими словами, функция showArrays() начнет выполняться после того, как документ (X)HTML будет загружен и проанализирован.

Я рекомендую вам поместить код JavaScript в отдельный файл и использовать следующий код HTML в разделе head: <script type="text/javascript" src="yourfilepath.js"></script>. Тогда вы также можете использовать события window.onload и onclick вместо метода document.addEventListener().

Когда вы это сделаете, вы можете поместить код внутри функции showArrays вне ее тела и удалить функцию.

Например:

window.onload = function()
{
  var link = document.getElementById("clickHandler");
  link.onclick = getArrays;
}

Это считается гораздо лучшей практикой.

Полный пример

В файле script.js:

//This is the beginning of the script...

    function getArrays() {
        var ddlValArray = new Array();
        var ddlTextArray = new Array();
        var ddl = document.getElementById("ddlFlavors");

        for (i=0; i<ddl.options.length; i++) {
            ddlValArray[i] = ddl.options[i].value;
            ddlTextArray[i] = ddl.options[i].text;
            alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
        }
    }

window.onload = function()
{
  var link = document.getElementById("clickHandler");
  link.onclick = getArrays;
}

Внутри вашей HTML-головы:

<script type="text/javascript" src="script.js"></script>

В большинстве случаев лучше писать JavaScript отдельно от файла HTML, как и CSS. Таким образом, вы сделаете свой HTML-код более аккуратным и организованным.

person Luka    schedule 20.12.2012
comment
Однако window.onload вызывает утечку памяти в IE, тогда как addEventListener и removeEventListener могут решить эту проблему относительно легко - person Elias Van Ootegem; 21.12.2012