Wybierz element poprzez dokładne dopasowanie jego zawartości


160

W porządku, zastanawiam się, czy jest sposób, aby :contains()selektor jQuery wybierał elementy tylko z wpisanym ciągiem

na przykład -

<p>hello</p>
<p>hello world</p>

$('p:contains("hello")').css('font-weight', 'bold');

Selektor wybierze oba pelementy i uczyni je pogrubionymi, ale chcę, aby wybierał tylko pierwszy.


Cóż, możesz zastąpić :containsselektor własnym kodem, ale nie sądzę, że o to Ci chodziło?
Blazemonger


Możesz zdefiniować niestandardowy selektor: stackoverflow.com/questions/12244929/ ...
BLSully


Odpowiedzi:


214

Nie, nie ma selektora jQuery (lub CSS), który to robi.

Możesz łatwo użyć filter:

$("p").filter(function() {
    return $(this).text() === "hello";
}).css("font-weight", "bold");

To nie jest selektor , ale spełnia swoje zadanie. :-)

Jeśli chcesz obsłużyć spacje przed lub po „cześć”, możesz dodać $.trimtam znak :

return $.trim($(this).text()) === "hello";

W przypadku przedwczesnych optymalizatorów, jeśli nie obchodzi Cię, że nie pasuje <p><span>hello</span></p>i jest podobny, możesz uniknąć wywołań $i text, używając innerHTMLbezpośrednio:

return this.innerHTML === "hello";

... ale musiałbyś mieć wiele akapitów, aby miało to znaczenie, tak wiele, że prawdopodobnie najpierw miałbyś inne problemy. :-)


7
Może również chcieć, aby $.trimprzed dokonaniem porównania pojawił się jakiś zbłąkany biały znak.
Blazemonger

Z jakiegoś powodu musiałem użyć „==”, aby to zadziałało, zamiast „===”.
Stephan

3
@Stephan: Jeśli porównujesz z liczbą, musiałbyś albo użyć ==( == 2), albo umieścić liczbę w ciągu ( === "2"), ponieważ wartość, z której otrzymujesz text()lub innerHTMLjest zawsze ciągiem. Jeśli porównujesz ze stringiem, nie ma znaczenia, czy użyjesz, ==czy ===.
TJ Crowder

Szkoda, że ​​jQuery zaimplementowało, :containsco jest trochę bardziej złożone, ale nie zaimplementowało selektora do dokładnego dopasowania tekstu. = {
Paulo Bueno

54

Spróbuj dodać pseudo funkcję rozszerzającą:

$.expr[':'].textEquals = $.expr.createPseudo(function(arg) {
    return function( elem ) {
        return $(elem).text().match("^" + arg + "$");
    };
});

Następnie możesz:

$('p:textEquals("Hello World")');

2
świetne rozwiązanie: mały dodatek: aby upewnić się, że nie nadpisujesz istniejącego wyrażenia, zrobiłbym:$.expr[':'].textEquals = $.expr[':'].textEquals || $.expr.createPseudo(function(arg) {
Mischa Molhoek

9

Aby to osiągnąć, możesz użyć funkcji filter () jQuery .

$("p").filter(function() {
// Matches exact string   
return $(this).text() === "Hello World";
}).css("font-weight", "bold");

9

Więc odpowiedź Amandu w większości działa. Używając go na wolności, napotkałem jednak pewne problemy, w których rzeczy, których bym się spodziewał, nie zostały znalezione. Dzieje się tak, ponieważ czasami istnieje przypadkowa biała przestrzeń otaczająca tekst elementu. Wierzę, że jeśli szukasz „Hello World”, nadal chciałbyś, aby pasowało do „Hello World”, a nawet „Hello World \ n”. Dlatego właśnie dodałem do funkcji metodę „trim ()”, która usuwa otaczające białe znaki i zaczęła działać lepiej.

Konkretnie...

$.expr[':'].textEquals = function(el, i, m) {
    var searchText = m[3];
    var match = $(el).text().trim().match("^" + searchText + "$")
    return match && match.length > 0;
}

Zwróć też uwagę, że ta odpowiedź jest bardzo podobna do opcji Wybierz link według tekstu (dopasowanie ścisłe)

I dodatkowa uwaga ... trimusuwa tylko białe znaki przed i po wyszukanym tekście. Nie usuwa białych znaków w środku wyrazów. Uważam, że jest to pożądane zachowanie, ale możesz to zmienić, jeśli chcesz.


5

Znalazłem sposób, który działa dla mnie. Nie jest w 100% dokładna, ale eliminuje wszystkie ciągi zawierające więcej niż tylko słowo, którego szukam, ponieważ sprawdzam, czy ciąg nie zawiera również pojedynczych spacji. Nawiasem mówiąc, nie potrzebujesz tych "". jQuery wie, że szukasz łańcucha. Upewnij się, że w części: zawiera () jest tylko jedna spacja, w przeciwnym razie nie będzie działać.

<p>hello</p>
<p>hello world</p>
$('p:contains(hello):not(:contains( ))').css('font-weight', 'bold');

I tak, wiem, że to nie zadziała, jeśli masz takie rzeczy <p>helloworld</p>


1
Sprytne użycie prostych dopasowań z zawartością (..) bez użycia filtra lub rozszerzenia! Nie będzie działać na niczym, co wymaga spacji w pierwszym zawiera (..), ale próbuje znaleźć rozwiązanie tego problemu. Dzięki!
JoePC

3

Jak wspomniany powyżej TJ Crowder, funkcja filtrująca czyni cuda. W moim przypadku to nie działało. Musiałem przeszukać wiele tabel i odpowiadające im znaczniki td wewnątrz elementu div (w tym przypadku okna dialogowego jQuery).

$("#MyJqueryDialog table tr td").filter(function () {
    // The following implies that there is some text inside the td tag.
    if ($.trim($(this).text()) == "Hello World!") {
       // Perform specific task.
    }
});

Mam nadzieję, że to komuś pomoże!


Jestem całkiem nowy w jquery, ale pomyślałbym, że lepiej byłoby użyć each () zamiast filter (), ponieważ celem filter jest zwrócenie podtablicy. Ale zdecydowanie zainspirowałem rozwiązanie, ponieważ miałem te same problemy :)
JeopardyTempest

0

Jednowierszowy, który współpracuje z bibliotekami alternatywnymi do jQuery:

$('p').filter((i, p) => $(p).text().trim() === "hello").css('font-weight', 'bold');

A to jest odpowiednikiem a:contains("pattern")selektora jQuery :

var res = $('a').filter((i, a) => $(a).text().match(/pattern/));

-4

Pomoże w tym .first ()

$('p:contains("hello")').first().css('font-weight', 'bold');

Jasne ... w tym konkretnym przypadku. co, jeśli zamówienie nie jest znane w czasie tworzenia?
BLSully
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.