Mencari metode find jQuery (..) yang menyertakan node saat ini

134

Metode traversal jQuery find (..) tidak menyertakan simpul saat ini - dimulai dengan anak-anak dari simpul saat ini. Apa cara terbaik untuk memanggil operasi pencarian yang menyertakan simpul saat ini dalam algoritme yang cocok? Melihat melalui dokumen tidak ada yang langsung melompat ke arahku.

John K.
sumber

Jawaban:

153

Untuk jQuery 1.8 dan yang lebih tinggi, Anda bisa menggunakan .addBack(). Dibutuhkan pemilih sehingga Anda tidak perlu memfilter hasilnya:

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

Sebelum jQuery 1.8 Anda terjebak .andSelf(), (sekarang tidak digunakan lagi dan dihapus) yang kemudian membutuhkan pemfilteran:

object.find('selector').andSelf().filter('selector')
Robert
sumber
5
Saya telah menggabungkan ini sebagai plugin jquery.findIncludeSelf, terdaftar dengan bower. Lihat github.com/ronen/jquery.findIncludeSelf
ronen
18
@ronen File tambahan untuk sesuatu yang dapat dilakukan dalam satu baris? Terima kasih tapi tidak, terima kasih.
6
@ prc322 file tambahan tidak mengganggu saya untuk penyebaran yang menggabungkan semua javascript ke dalam satu file. Secara umum saya lebih suka menggunakan metode perpustakaan (diuji) bahkan untuk hal-hal sederhana, daripada mengacaukan kode saya dengan hal-hal yang saya temukan lebih sulit untuk dibaca dan yang memperkenalkan lebih banyak kemungkinan untuk bug. Dalam hal ini khususnya, IMHO kebutuhan untuk menentukan 'selector'dua kali membuat enkapsulasi lebih diinginkan. YMMV
ronen
Ok jadi saya mungkin menjadi tebal tetapi Anda tidak perlu menentukan 'selector'dua kali, (seperti yang disebutkan oleh @ronen), tidak bisakah Anda menggunakan saja object.parent().find('selector')??? - itu dikatakan saya suka ide lib yang melakukannya untuk Anda.
Sam
8
@ circa1983 object.parent().find('selector')termasuk saudara kandung objectdan keturunan mereka.
Robert
41

Anda tidak dapat melakukan ini secara langsung, yang paling dekat yang dapat saya pikirkan adalah menggunakan .andSelf()dan menelepon .filter(), seperti ini:

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

Sayangnya .andSelf()tidak mengambil pemilih, yang akan berguna.

Nick Craver
sumber
7
Anda bahkan menambahkan komentar ke halaman jquery tepat setelah menjawab pertanyaan ini api.jquery.com/andSelf/#comment-50124533 Nah, itu sudah teliti. Bagus! Saya melakukan uji tuntas dan 'Menyukai' yang itu juga.
John K
2
Yang kedua akan sangat lambat. Yang pertama hanya lambat.
Tgr
@Tgr - Saya tidak setuju, meskipun yang pertama tidak boleh bahwa acara kecuali jika Anda berurusan sedang dengan sangat sejumlah besar elemen. Jika Anda tidak perlu rantai, Anda dapat melewati pemfilteran ulang elemen-elemen itu dengan pasti.
Nick Craver
3
Menariknya, closest(..)termasuk elemen DOM saat ini dan naik pohon sedangkan semua metode traversal turun-pohon seperti find(..)dll tidak cocok dengan elemen saat ini. Seolah-olah tim jQuery sengaja mengimplementasikan ini tanpa tumpang tindih ketika kedua operasi digunakan bersama untuk pencarian vertikal penuh.
John K
17
Ingatlah bahwa .andSelf () telah ditinggalkan sejak v1.8 dan diganti dengan .addBack () yang menggunakan pemilih sebagai argumen. Lihat api.jquery.com/addBack
kkara
9

Menetapkan

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

lalu gunakan

$.findSelf(selector);

dari pada

$find(selector);

Sayangnya jQuery tidak memiliki fitur bawaan ini. Sangat aneh selama bertahun-tahun pembangunan. Penangan AJAX saya tidak diterapkan ke beberapa elemen teratas karena cara kerja .find ().

Dmitriy Sintsov
sumber
Ini buggy. Itu menambahkan semua "diri", bahkan jika hanya satu dari mereka yang cocok ... - Salah satu alasan untuk bug ini adalah metode jQuery bernama crappily ...
Robert Siemer
Saya mencoba memperbaiki bug yang telah Anda laporkan. Apakah itu berfungsi dengan baik sekarang?
Dmitriy Sintsov
Sebagian besar jawaban lain digunakan di filter()sana, yang lebih masuk akal.
Robert Siemer
5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

Anda dapat menyimpan $('selector')dalam variabel untuk speedup. Anda bahkan dapat menulis fungsi khusus untuk ini jika Anda sangat membutuhkannya:

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

$('selector').andFind('otherSelector')
Tgr
sumber
Ini hanya berfungsi jika Anda memulai dengan pemilih, yang mungkin tidak terjadi. Juga, itu tidak benar $('selector').find('otherSelector').add($('otherSelector')), apa yang Anda miliki sekarang setara dengan .andSelf(). Terakhir, .andFind()filter tidak didasarkan pada ekspresi, Anda harus .add($(this).filter(expr)):)
Nick Craver
@Nick Craver: yeah, saya lupa bagian penyaringan, diperbaiki sekarang. Tidak masalah jika $('selector')diganti dengan metode lain untuk mendapatkan objek jQuery (jika itu yang Anda maksud dengan tidak memulai dengan pemilih), add()bisa menangani apa saja seperti $()bisa.
Tgr
Maksud saya adalah bahwa Anda $('selector')mungkin $('selector').children('filter').closest('.class').last()... mungkin dalam rantai dan Anda tidak tahu apa objek yang Anda tambahkan adalah, jadi solusi generik harus mengambil objek sebelumnya seperti yang dilakukan filter :)
Nick Craver
Saya masih tidak melihat mengapa itu menjadi masalah. thisadalah objek jQuery apa pun yang dipanggil oleh plugin. Bisa juga hasil dari rantai panggilan.
Tgr
5

Jawaban yang diterima sangat tidak efisien dan memfilter sekumpulan elemen yang sudah cocok.

//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);
erikrestificar
sumber
3

Jika Anda ingin rantai bekerja dengan benar, gunakan snippet di bawah ini.

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

Setelah panggilan fungsi akhir mengembalikan elemen #foo.

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

Tanpa mendefinisikan plugin tambahan, Anda akan terjebak dengan ini.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');
SeregPie
sumber
Ah, tidak ... Jika thislebih dari satu elemen this.is()sudah puas jika hanya satu yang cocok.
Robert Siemer
3

Jika Anda mencari tepat satu elemen , baik elemen saat ini atau elemen di dalamnya, Anda dapat menggunakan:

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

Jika Anda mencari beberapa elemen yang dapat Anda gunakan:

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

Penggunaan andSelf/ andBacksangat jarang, tidak yakin mengapa. Mungkin karena masalah kinerja beberapa orang yang disebutkan sebelum saya.

(Sekarang saya perhatikan bahwa Tgr sudah memberikan solusi kedua)

oriadam
sumber
2

Saya tahu ini adalah pertanyaan lama, tetapi ada cara yang lebih benar. Jika pesanan itu penting, misalnya ketika Anda mencocokkan pemilih seperti :first, saya menulis sedikit fungsi yang akan mengembalikan hasil yang sama persis seolah-olah find()termasuk set elemen saat ini:

$.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);
};

Itu tidak akan efisien dengan cara apa pun, tapi itu yang terbaik yang saya buat untuk menjaga ketertiban.

Justin Warkentin
sumber
1

Saya pikir andSelfadalah apa yang Anda inginkan:

obj.find(selector).andSelf()

Perhatikan bahwa ini akan selalu menambah kembali simpul saat ini, apakah cocok dengan pemilih.

interjay
sumber
1

Jika Anda benar-benar mencari di simpul saat ini, Anda cukup melakukannya

$(html).filter('selector')
mikewasmike
sumber
0

Saya mencoba menemukan solusi yang tidak terulang kembali (yaitu tidak memasukkan pemilih yang sama dua kali).

Dan ekstensi jQuery kecil ini melakukannya:

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

Ini menggabungkan find()(hanya keturunan) dengan filter()(hanya set saat ini) dan mendukung argumen apa pun yang dimakan. The pushStack()memungkinkan untuk .end()bekerja seperti yang diharapkan.

Gunakan seperti ini:

$(element).findWithSelf('.target')
Robert Siemer
sumber
-2

Inilah kebenaran yang benar (tapi menyedihkan):

$(selector).parent().find(oSelector).filter($(selector).find('*'))

http://jsfiddle.net/SergeJcqmn/MeQb8/2/

Serge
sumber
tidak bekerja dengan node yang terlepas (dan dokumen itu sendiri), namun.
John Dvorak
2
Eh, tidak, ini akan menghapus $(selector)dirinya sendiri dari set di semua kasus.
John Dvorak