jQuery .live () vs .on () метод для додавання події клацання після завантаження динамічного html


217

Я використовую jQuery v.1.7.1, де метод .live () очевидно застарілий.

Проблема, яка у мене виникає, полягає в тому, що при динамічному завантаженні HTML в елемент за допомогою:

$('#parent').load("http://..."); 

Якщо я спробую після цього додати подію натискання, вона не реєструє подію, використовуючи один із цих способів:

$('#parent').click(function() ...); 

або

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

Який правильний спосіб досягти цієї функціональності? Мені здається, що для мене працює .live (), але я не повинен використовувати цей метод. Зауважте, що #child - динамічно завантажений елемент.

Дякую.


25
Чому ви кажете "нібито застаріле" ? Ви не вірите документам?

6
Це не нібито застарів: він є застарілим. Якщо ви подивитесь на jQuery doco,.live() він говорить про те, як переписати існуючі способи .live()використання .delegate()або .on()(залежно від того, ви користуєтеся версією 1.7 або більше). Зауважте, що якщо ви додаєте обробник з .click()"згодом", як ви згадували, тобто після динамічного завантаження елементів, він повинен працювати - єдину проблему намагаються призначити .click() перед динамічним завантаженням елементів.
nnnnnn

Я змінив формулювання на «мабуть», оскільки це в основному те, що я мав на увазі. У будь-якому разі я зараз розумію, що очевидно, оскільки подія .load () є асинхронною, то елемент #child міг бути надійно розпізнаний у обробці успіху, що має сенс.
Шон Томан

Відповіді:


606

Якщо ви хочете, щоб обробник кліків працював для елемента, який динамічно завантажується, тоді ви встановлюєте обробник подій на батьківський об'єкт (який не завантажується динамічно) і даєте йому селектор, який відповідає вашому динамічному об'єкту на зразок цього:

$('#parent').on("click", "#child", function() {});

Обробник подій буде приєднаний до #parentоб'єкта, і щоразу, коли подія натискає на нього, на якій виник #child, він запустить ваш обробник кліків. Це називається делегованою обробкою події (обробка події делегована батьківському об'єкту).

Це робиться таким чином, оскільки ви можете приєднати подію до #parentоб'єкта навіть тоді, коли #childоб’єкт ще не існує, але коли він пізніше існує та отримує натискання на нього, подія клацання буде міхувати до #parentоб'єкта, воно побачить, що воно виникло #childі є обробник подій для натискання #childта запуску вашої події.


23
Чудове пояснення! Я ніколи раніше не міг обернути голову live()проти, on()але сьогодні ввечері я знову вирішив спробувати, і ваше пояснення одразу показало, що я пропускав весь час. Дякую!
MikeSchinkel

6
Мільйон підйомів . Я почав використовувати нокаут, перш ніж зрозумів, що це можливо в jQuery для динамічно створених дітей, дуже дякую.
Брок Хенслі

9
Вам варто подумати над написанням книги чи чогось іншого: ваш маленький текст був мені більш корисним, ніж повна сторінка в документах jQuery про « on () ». Дуже дякую!
Холестерин

@ jfriend00 Ви знаєте, як ми можемо застосувати цей самий процес до ситуації, що наближається, коли не наводиться? чи є джерело, яке говорить про це?
klewis

@blackhawk - див. цю відповідь . Ви можете зареєструватися для mouseenterі mouseleaveподій і випробувань всередині обробника , який один був викликаний. Подія псевдо "наведення" jQuery недоступна при делегуванні.
jfriend00

33

Спробуйте це:

$('#parent').on('click', '#child', function() {
    // Code
});

З $.on()документації:

Обробники подій прив'язані лише до обраних на даний момент елементів; вони повинні існувати на сторінці в той момент, коли ваш код робить дзвінок .on().

Ваш #childелемент не існує, коли ви дзвоните $.on()на нього, тому подія не пов'язана (на відміну від $.live()). #parentОднак вони існують, тому прив'язка події до цього нормальна.

Другий аргумент в моєму коді вище , діють як «фільтр» спрацьовують тільки в разі , якщо подія ого до #parentз #child.


Якщо я називаю метод $ .on () після методу $ .load (), то чому б у цьому пункті не існував елемент #child?
Шон Томан

6
@SeanThoman - вам доведеться викликати це від обробника успіху .load()методу - а не від коду після .load()методу. #childвідомо, що завантажується лише тоді, коли обробник успіху реально виконує, а не раніше.
jfriend00

і навіть тоді потрібен час, щоб вставити всі дані, які ви отримали назад, у DOM, це означає, що вони можуть не підключитися. Останнім часом я багато працюю над додатками на одній сторінці, і моїм стандартом є var $ body = $ ('body'); $ body.on ("подія", ".element / # class", функція (e) {}); за все. 1 селектор. Не хвилюйтеся про те, що завантажено чи не завантажено.
lupos

21

$(document).on('click', '.selector', function() { /* do stuff */ });

EDIT: Я надаю трохи більше інформації про те, як це працює, тому що ... слова. На цьому прикладі ви розміщуєте слухача на весь документ.

Коли ви підбираєте clickбудь-який елемент (и) .selector, подія перетворюється на основний документ - доки немає інших слухачів, які називають event.stopPropagation()метод виклику, - який би перейшов у бульбашку події до батьківських елементів.

Замість прив’язки до певного елемента чи набору елементів ви слухаєте будь-які події, що надходять із елементів, які відповідають вказаному селектору. Це означає, що ви можете одночасно створити одного слухача, який автоматично відповідатиме існуючим елементам, а також будь-яким динамічно доданим елементам.

Це розумно з кількох причин, включаючи продуктивність та використання пам'яті (у великих масштабах)

Редагувати:

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


23
Він спробував $(element).on(...). Це $(document).on(...,element,...). Різні звірі.
cHao

@ArnoldRoa так, краща продуктивність. у вас не буде слухача для кількох дітей, не потрібно повторно застосовувати слухача будь-коли, коли DOM буде змінено, і події за замовчуванням піднімаються до DOM. Запустити один раз, і кожна дитина, що відповідає селектору, запустить цю функцію при натисканні.
L422Y

@ L422Y коментар тут дуже оманливий. Якщо вам цікаво наслідки щодо продуктивності, погляньте на коментар @ jfriend00 щодо відповіді @ Джареда
Gust van de Wal

@GustvandeWal Як це вводити в оману? Якщо ви перейдете і випустите сто доларів (це) .on (...) проти прослуховування події один раз на батьківському елементі, це значно ефективніше.
L422Y

Ви говорите лише про приєднання подій. У вузьких місцях роботи в реальному світі є занадто багато слухачів, які звільняються (наприклад, ті, які ви делегуєте), а не велика кількість елементів, які потребують приєднаної до них події.
Густ ван де Валь

12

Еквівалент .live () у 1.7 виглядає так:

$(document).on('click', '#child', function() ...); 

В основному, перегляньте документ для подій клацання і відфільтруйте їх для #child.


Тому що так обробник подій приєднується до документа (як .live()це робиться).
cHao

17
Одна з причин, яка .live()зараз застаріла, полягає в тому, що погано розміщувати всі обробники подій у реальному часі на об'єкті документа. Все може дійсно, дуже сповільнитись. Події мають не тільки переповнювати весь документ, але й у вас може бути багато обробників подій, які слід переглянути на об'єкті документа. Основна перевага .on()полягає в тому, що ви можете приєднати його до батьківського об'єкта, який набагато ближче до фактичного об’єкта і різко підвищити продуктивність. Отже ... Я б не рекомендував використовувати .on()об'єкт документа. Набагато краще вибрати ближчий батьківський об’єкт.
jfriend00

Дякуємо за роз’яснення. Оскільки це варте того, щоб ефективність подій була значно покращена в режимі on (), тому це має бути менше питань, ніж раніше. Якщо ви прив’язуєтесь до батьків, я б припускав, що це повинен бути батько, який існує в документі, готовому або ви побачите подібні проблеми.
Джаред

У гіршому випадку, це робить емулювати застарілий .live()підхід; однак можливість контролювати делегування, безумовно, вигідна.
Ден Лугг

9

Я знаю, що відповідь трохи пізно, але я створив поліфункцію для методу .live (). Я тестував його в jQuery 1.11, і, здається, він працює досить добре. Я знаю, що нам слід застосовувати метод .on (), де це можливо, але у великих проектах, де неможливо перетворити всі .live () виклики в еквівалентні дзвінки .on () з будь-якої причини, може бути наступне робота:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

Просто включіть його після завантаження jQuery і перед тим, як зателефонувати в live ().


5

.on () призначений для jQuery версії 1.7 та вище. Якщо у вас старіша версія, скористайтеся цією:

$("#SomeId").live("click",function(){
    //do stuff;
});

8
ОП каже: "Я використовую jQuery v.1.7.1"
Selvakumar Arumugam

1
@ jfriend - чому б не опублікувати власну відповідь замість того, щоб скасувати мою? Я використовую live () щодня зі всіма версіями молодшими 1,6 і це чудово. Я можу бачити, що ви добре читаєте документацію, але іноді це більше допомогти втілити щось на практиці для людини. .live () працює. Період.
Метт Кашатт

5
@MatthewPatrickCashatt - я опублікував власну відповідь і не спростував вашу - не робіть таких сліпих припущень. Попередня версія 1.7 .delegate()виконує набагато кращі .live()результати, тому саме jQuery doc рекомендує її та знецінює .live(). Так, .live()все ще працює, але відповіді тут на ТА повинні рекомендувати кращий спосіб робити. Я бачив це 20 разів тут, на SO. Якщо ви .live()надсилаєте код тут на SO, він буде знятий (як правило, не я, якщо тільки щось інше серйозно не так).
jfriend00

1
Я не спровокував, але, .live()безумовно, працює навіть у версії 1.7, ви все одно повинні використовуватись, .delegate()або .on()тому, що з усієї .live()причини був застарілий. Поки ви зазначаєте, що зміна синтаксису для двох нових функцій або буде працювати нормально.
nnnnnn

1
@ jfriend00- Ви абсолютно праві. Довгий день. Мої вибачення.
Метт Кашатт

3

Я використовував "live" у своєму проекті, але один мій друг запропонував мені використовувати "on", а не жити. І коли я намагався використати це, я відчув проблему, як у вас.

На моїх сторінках я динамічно створюю рядки таблиць кнопок і багато матеріалів. але коли я користуюся магією, зник.

Інші рішення, такі як використовувати його, як дитина, просто викликають ваші функції кожного разу при кожному натисканні. Але я знаходжу спосіб зробити це повторним, і ось рішення.

Напишіть свій код:

function caller(){
    $('.ObjectYouWntToCall').on("click", function() {...magic...});
}

Виклик виклику (); після створення об’єкта на цій сторінці.

$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();

Таким чином, ваша функція викликається, коли передбачається не кожне клацання сторінки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.