Шукаєте метод jQuery find (..), який включає поточний вузол


134

Метод обходу jQuery find (..) не включає поточний вузол - він починається з дітей поточного вузла. Який найкращий спосіб викликати операцію пошуку, яка включає поточний вузол у його алгоритмі відповідності? Переглядаючи документи, одразу нічого не вискакує на мене.

Відповіді:


153

Для jQuery 1.8 і новіших версій ви можете використовувати .addBack(). Він займає селектор, тому вам не потрібно фільтрувати результат:

object.find('selector').addBack('selector')

До jQuery 1.8 вас затримали .andSelf()(тепер застарілі та видалені), які потім потребували фільтрації:

object.find('selector').andSelf().filter('selector')

5
Я поєднав це як плагін jquery.findIncludeSelf, зареєстрований на bower. Дивіться github.com/ronen/jquery.findIncludeSelf
ronen

18
@ronen Додатковий файл для чогось, що можна зробити в одному рядку? Дякую, але не дякую.

6
@ prc322 додатковий файл не турбує мене за розгортаннями, які в будь-якому випадку об'єднують весь javascript у єдиний файл. Як правило, я віддаю перевагу використанню (перевірених) методів бібліотеки навіть для простих речей, а не захаращувати свій код речами, які мені важче читати, і що дає більше можливостей для помилок. Зокрема, у цьому випадку, IMHO необхідність уточнювати 'selector'двічі робить інкапсуляцію додатково бажаною. YMMV
ronen

Гаразд, я можу бути товстим, але тому вам не доведеться вказувати 'selector'двічі (як згадував @ronen), ви не могли просто використати object.parent().find('selector')??? - якщо говорити, мені подобається ідея ліб, яка робить це за тебе.
Сем

8
@ circa1983 object.parent().find('selector')включає в себе братів objectі сестер та їхніх нащадків.
Роберт

41

Ви не можете цього зробити безпосередньо, найближчим, про що я можу подумати, - це використання .andSelf()та дзвінки .filter(), як це:

$(selector).find(oSelector).andSelf().filter(oSelector)
//or...
$(selector).find('*').andSelf().filter(oSelector);

На жаль .andSelf(), не бере селектор, що було б зручно.


7
Ви навіть додали коментар на сторінку jquery одразу після відповіді на це запитання api.jquery.com/andSelf/#comment-50124533 Тепер це ґрунтовність. Приємно! Я зробив належну ретельність і "сподобався" і тому.
Джон К

2
Другий був би розумно повільним. Перший просто просто повільний.
Тгр

@Tgr - Я не погоджуюся, хоча перше не повинно бути таким шоу, якщо ви не маєте справу з дуже великою кількістю елементів. Якщо вам не потрібно ланцюг, ви можете точно пропустити повторну фільтрацію цих елементів.
Нік Крейвер

3
Цікаво, що closest(..)включає в себе поточний елемент DOM та дерево, тоді як усі способи обходу вниз по дереву, наприклад, find(..)тощо, не відповідають поточному елементу. Це як би команда jQuery цілеспрямовано реалізувала їх, щоб не перетинатися, коли обидві операції використовуються разом для повного вертикального пошуку.
Джон К

17
Майте на увазі, що .andSelf () був застарілим з версії 1.8 і замінений на .addBack (), який бере аргумент селектора. Дивіться api.jquery.com/addBack
kkara

9

Визначте

$.fn.findSelf = function(selector) {
    var result = this.find(selector);
    this.each(function() {
        if ($(this).is(selector)) {
            result.add($(this));
        }
    });
    return result;
};

потім використовуйте

$.findSelf(selector);

замість

$find(selector);

На жаль, у jQuery немає цієї вбудованої. Дійсно дивно за стільки років розвитку. Мої обробники AJAX не застосовувалися до деяких основних елементів через те, як працює .find ().


Це баггі. Це додає все "Я", навіть якщо відповідає лише одна з них ... - Однією з причин цієї помилки є шалено названий метод jQuery ...
Роберт Сімер

Я спробував виправити помилку, про яку ви повідомили. Чи працює він зараз правильно?
Дмитро Сінцов

filter()Там використовується більшість інших відповідей , що має більше сенсу.
Роберт Сімер

5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

Ви можете зберігати $('selector')змінну для прискорення. Ви навіть можете написати для цього спеціальну функцію, якщо вона вам дуже потрібна:

$.fn.andFind = function(expr) {
  return this.find(expr).add(this.filter(expr));
};

$('selector').andFind('otherSelector')

Це працює лише в тому випадку, якщо ви починаєте з селектора, але це може бути не так. Крім того, це неправильно, це було б $('selector').find('otherSelector').add($('otherSelector'))те, що у вас зараз є рівнозначним .andSelf(). Нарешті, .andFind()не фільтрується на основі виразу, вам потрібно буде .add($(this).filter(expr)):)
Нік Крейвер

@ Nick Craver: так, я забув фільтруючу частину, виправлену зараз. Не важливо, чи $('selector')замінений він яким-небудь іншим методом отримання об'єкта jQuery (якщо це саме те, що ви мали на увазі, не починаючи з селектора), add()може впоратися з чим завгодно так само $().
Тгр

Моя думка полягала в тому, що ваш $('selector')може бути $('selector').children('filter').closest('.class').last()... це може бути ланцюжок, і ви не маєте уявлення, що це об’єкт, який ви додаєте, тому загальне рішення повинно приймати попередній об’єкт, як це робить фільтр :)
Нік Крейвер

Я досі не бачу, чому це було б проблемою. thisбудь-який об'єкт jQuery, плагін був викликаний. Це може бути так само результатом ланцюжка викликів.
Тгр

5

Прийнята відповідь дуже неефективна і фільтрує набір елементів, які вже відповідні.

//find descendants that match the selector
var $selection = $context.find(selector);
//filter the parent/context based on the selector and add it
$selection = $selection.add($context.filter(selector);

3

Якщо ви хочете, щоб ланцюг працював належним чином, скористайтеся фрагментом нижче.

$.fn.findBack = function(expr) {
    var r = this.find(expr);
    if (this.is(expr)) r = r.add(this);
    return this.pushStack(r);
};

Після виклику функції завершення повертає елемент #foo.

$('#foo')
    .findBack('.red')
        .css('color', 'red')
    .end()
    .removeAttr('id');

Не визначаючи зайвих плагінів, ви зациклювались на цьому.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');

Ага, ні ... Якщо thisбільш ніж один елемент this.is()вже задоволений, якщо відповідає лише один із них.
Роберт Сімер

3

Якщо ви шукаєте саме один елемент , або поточний елемент, або один всередині нього, ви можете використовувати:

result = elem.is(selector) ? elem : elem.find(selector);

Якщо ви шукаєте кілька елементів, ви можете використовувати:

result = elem.filter(selector).add(elem.find(selector));

Використання andSelf/ andBackдосить рідкісне, не знаю чому. Можливо, через проблеми виступу деякі хлопці згадували переді мною.

(Я помітив, що Tgr вже дав це друге рішення)


2

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

$.fn.findAll = function(selector) {
  var $result = $();

  for(var i = 0; i < this.length; i++) {
    $result = $result.add(this.eq(i).filter(selector));
    $result = $result.add(this.eq(i).find(selector));
  }

  return $result.filter(selector);
};

Це не буде ефективно будь-яким способом, але це найкраще, що я придумав, щоб підтримувати належний порядок.


1

Я думаю andSelf, що ти хочеш:

obj.find(selector).andSelf()

Зауважте, що це завжди додаватиме поточний вузол, незалежно від того, чи відповідає він селектору.


1

Якщо ви суворо дивитесь у поточний вузол, ви просто це зробите

$(html).filter('selector')

0

Я намагався знайти рішення, яке не повториться (тобто не входити в один і той же селектор двічі).

І це крихітне розширення jQuery:

jQuery.fn.findWithSelf = function(...args) {
  return this.pushStack(this.find(...args).add(this.filter(...args)));
};

Він поєднує find()(лише нащадків) з filter()(лише поточний набір) і підтримує будь-які аргументи, які обидва є. pushStack()Дозволяє .end()працювати , як очікувалося.

Використовуйте так:

$(element).findWithSelf('.target')

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