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

JavaScript

эти странные ошибки

Я ничего не писал в течение двух недель. В последнее время я немного запаниковал из-за своих знаний. Я хотел бы поделиться ошибкой, с которой я столкнулся некоторое время назад. Эта ошибка связана с методом on jquery, привязанным к интерактивным событиям, похожим на $ ('#point').on(' Click', '.read-more', function() {}) и другие коды вызывают многократное выполнение программы. Об этом многие писали в статье, а также говорили, что метод off использовали для отвязки, но указать на проблему не удалось.Природа проблемы почти игнорирует тот факт, что суть проблемы вызвана делегированием события. Без лишних слов давайте нажмем на код, который я вижу каждый день:
Первый:

    $(document).on('click', function (e) {
        consol.log('jquery事件绑定')
    });

Второй:

   document.addEventListener('click',function (e) {
        consol.log('原生事件绑定')            
   });

Третий:

   var id = setInterval(function () {
        console.log('定时器循环事件绑定')
   },1000);

Приведенный выше код, я думаю, что многие союзники будут писать его каждый день, кажущаяся простой привязкой событий часто может принести нам неожиданные результаты, особенно в этом SPA, когда так популярно применение частичного обновления страниц AJAX. Что такое привязка события, вызывающая повторное выполнение программы? Кажется, что это дело не так просто прояснить, давайте проиллюстрируем это тестовым кодом. Вы можете скопировать его локально и попробовать сами:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button class="add_but">点击</button>
<div id="point">fdfsdf
</div>
<script src="https://cdn.bootcss.com/jquery/1.8.3/jquery.js"></script>    
<script>
    var count=1;
    var example = {
        getData:function () {
            var data ={
                content:'df'+count++,
                href:''
            };
            this.renderData(data);
        },
        renderData:function (data) {
            document.getElementById('point').innerHTML='<div>this is a '+data.content+'点此<a class="read-more" href="javasript:;">查看更多</a></div>';
           $('#point').on('click','.read-more',function () {
            alert('事故发生点');
        })
/*            setInterval(function () {
                console.log('fdfdfg');
            },2000);*/
            /*用冒泡来绑定事件,类似于Jquery的on绑定事件*/
        /*  document.querySelector('body').addEventListener('click',function (e) {
                if(e.target.classList.contains('read-more')){
                    alert('事故发生点');
                }
            })*/

        }
    }  ;
    document.querySelector('.add_but').addEventListener('click',function (e) {
        example.getData();
        e.stopImmediatePropagation();
    });
</script>
</body>
</html>

Выше приведен фрагмент тестового кода, который я написал, чтобы прояснить этот вопрос, вы можете скопировать его и попробовать. Когда мы нажимаем кнопку страницы, инициируем вызов функции example.getData() и имитируем ajax для успешного получения данных, содержимое класса элемента с именем point на странице будет обновлено в соответствии с локальным и в то же время будет загружено чтение в содержимом. Тег A привязан к событию, поэтому появляется нужный нам эффект. Когда элемент загружается в первый раз, страница нормальная, а «авария точка" появляется один раз. Когда запускается второе обновление, вы обнаружите, что оно появляется дважды. раз, когда в третий раз, вы обнаружите, что оно воспроизводится три раза, и так далее. . . . OMG, что не так с этой программой, я, очевидно, удаляю ранее связанные элементы перед тем, как каждое событие будет связано, почему, удаленный труп все еще чувствует себя движущимся, ну, выше, это первый раз, когда я столкнулся с этой восклицательной ситуацией.
Наконец, я спросил великого бога вокруг меня, и я вдруг понял, что исходная привязка всегда была там, и эта привязка хранится в месте, называемом очередью событий.Картинка, еле взгляните.

事件队列
очередь событий

восстановить правду

На самом деле приведенный выше код специально написан для тестирования.За исключением таймера, два других клика прописаны в обычном режиме.Повторного выполнения не произойдет.Нормальный код:

        // jquery 事件直接绑定的写法;
        $('#point .read-more').on('click',function () {
            alert('事故发生点');
        })
        // 原生JS 事件直接绑定的写法;
        document.querySelector('.read-more').addEventListener('click',function (e) {
            alert('事故发生点');
        })

Вы видите разницу?На самом деле вам не нужно всплывать, чтобы делегировать события, а привязывать события непосредственно к добавленным элементам. такСобытия Dom — это разумные, динамически добавляемые элементы, а затем динамически связываемые события для этого.После удаления элементов соответствующие события, привязанные к ним, будут фактически удалены из очереди связывания событий., вместо тестового кода выше создается впечатление, что после удаления элемента связанное с ним событие все еще находится в памяти.но помни, это недоразумение.Причина, по которой протестированный выше код создает у людей эту иллюзию, заключается в том, что мы не привязываем события к динамически добавляемым элементам, а только используем форму делегирования событий.На самом деле события привязываются к #point на элементе , который существует всегда, использует всплывающую подсказку событий, чтобы сообщить программе, что мы нажали на динамически добавленный элемент ссылки. В тесте для воспроизведения этого делегирования события использовался нативный js.Принцип jQuery при привязке события в основном такой же.

document.querySelector('body').addEventListener('click',function (e) {
     if(e.target.classList.contains('read-more')){
          alert('事故发生点');
      }
})

Способы избавления от ошибок

таймер

Эту ошибку проще всего сделать и, конечно, легче всего решить, потому что когда таймер установлен, он вернет значение, которое должно быть числом в таймере в очереди событий, подобно 9527; шаги установлены глобальная переменная, чтобы сохранить идентификатор возвращаемого значения и очищать установленный таймер по идентификатору каждый раз, когда вы устанавливаете таймер

     clearInterval(intervalId); //粗暴的写法
     intervalId&&clearInterval(intervalId); //严谨的写法
     intervalId=setInterval(function () {
                console.log('fdfdfg');
            },2000);  

Дом события

На самом деле, как мы сказали выше, самый прямой путь — не использовать делегирование событий, а использовать прямую привязку; если вы действительно хотите использовать делегирование событий для связывания событий, то есть отвязать. В jquery предусмотрена функция отмены привязки для отмены привязки событий, но после версии jquery 1.8 этот метод больше не рекомендуется, но рекомендуется метод отключения. Например, в приведенном выше методе делегирования события для отмены привязки вы можете использовать оператор $('#point').off('click','.read-more').

Неверное решение, добавить отметку

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

     var flag = false;
     var example = {
        getData: function () {
            var data = {
                content: 'df' + count++,
                href: ''
            };
            this.renderData(data);
        },
        renderData: function (data) {
            document.getElementById('point').innerHTML = '<div>this is a ' + data.content + '点此<a class="read-more" href="javasript:;">查看更多</a></div>';
            !flag && $('#point').on('click', '.read-more', function () {
                alert('事故发生点'+data.content);
            });
            flag = true;
        }
    };

Логично, похоже, нет проблем, но на ближайшем осмотре, обнаружил, что это проблема. Когда наше второе, третьего обновления, контента или всплывающих окон и POP-последовательное моделирование в первый раз после обновления CLICK CONTENT, или «точка несчастного случая DF1», а не содержимое и одинаковое приращение, а почему, ощущение в обратном обратном вызове Очередь события хранится отдельно вверх, данные - это глубокая копия, а не ссылка.Это действительно трудно понять, и я не знаю, почему. Если кто-то может объяснить это ясно, пожалуйста, дайте мне знать..

конец

Написано в конце, на самом деле, при написании некоторых программ события обязательно вызывают повторное выполнение программы. Такие ситуации возникают редко. Обычно это происходит, когда мы пишем плагины. Плагин должен адаптироваться к различным вызывающим средам. , поэтому это делается внутри плагина.Очень важно предотвратить ситуации, когда события связываются повторно.
Эта статья была впервые опубликована на: closetb.site
Все права защищены, пожалуйста, сохраните исходную ссылку для перепечатки :)