Potrafię to zrobić:
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
Oznacza to, że mogę pomyślnie pobrać wszystkie bezpośrednie elementy potomne myDiv
elementu, który ma klasę .foo
.
Problem w tym, że przeszkadza mi to, że muszę #myDiv
w selektorze zawrzeć , bo odpytuję na myDiv
element (więc jest oczywiście zbędne).
Powinienem móc zostawić #myDiv
wyłączone, ale wtedy selektor nie jest legalną składnią, ponieważ zaczyna się od >
.
Czy ktoś wie, jak napisać selektor, który pobiera tylko bezpośrednie dzieci elementu, na którym działa selektor?
javascript
dom
css-selectors
mattsh
źródło
źródło
Odpowiedzi:
Dobre pytanie. W czasie, gdy o to zapytano, uniwersalnie zaimplementowany sposób wykonywania „zapytań zakorzenionych w kombinatorze” (jak je nazywał John Resig ) nie istniał.
Teraz pseudoklasa : scope została wprowadzona. Nie jest obsługiwany w wersjach Edge ani IE [sprzed Chrominum], ale już od kilku lat jest obsługiwany przez Safari. Używając tego, twój kod może stać się:
Zauważ, że w niektórych przypadkach możesz także pominąć
.querySelectorAll
i użyć innych dobrych, staromodnych funkcji DOM API. Na przykład zamiastmyDiv.querySelectorAll(":scope > *")
ciebie mógłbyśmyDiv.children
na przykład po prostu napisać .W przeciwnym razie, jeśli nie możesz jeszcze polegać
:scope
, nie mogę wymyślić innego sposobu radzenia sobie z twoją sytuacją bez dodawania większej logiki niestandardowego filtru (np. ZnajdźmyDiv.getElementsByClassName("foo")
kogo.parentNode === myDiv
) i oczywiście nie jest idealny, jeśli próbujesz obsługiwać jedną ścieżkę kodu, która naprawdę chce po prostu pobrać dowolny łańcuch selektora jako wejście i listę dopasowań jako wyjście! Ale jeśli tak jak ja zadałeś to pytanie po prostu dlatego, że utknąłeś, myśląc „wszystko, co miałeś to młotek”, nie zapominaj, że istnieje wiele innych narzędzi, które oferuje również DOM.źródło
myDiv.getElementsByClassName("foo")
to nie to samo comyDiv.querySelectorAll("> .foo")
, bardziej przypominamyDiv.querySelectorAll(".foo")
(co faktycznie działa) w tym, że znajduje wszystkie potomne.foo
s, a nie tylko dzieci.<style scoped>
) nie mają nic wspólnego z:scope
pseudo-selektorem opisanym w tej odpowiedzi.Prawidłowym sposobem napisania selektora, który jest "zakorzeniony" w bieżącym elemencie, jest użycie
:scope
.Jednak obsługa przeglądarki jest ograniczona i będziesz potrzebować podkładki, jeśli chcesz z niej korzystać. W tym celu zbudowałem scopedQuerySelectorShim .
źródło
:scope
specyfikacja jest obecnie „wersją roboczą” i dlatego może ulec zmianie. Prawdopodobnie nadal będzie działać w ten sposób, jeśli / kiedy zostanie przyjęty, ale trochę za wcześnie, aby powiedzieć, że moim zdaniem jest to „właściwy sposób”.Oto elastyczna metoda napisana w waniliowym języku JS, która umożliwia uruchomienie zapytania selektora CSS tylko dla bezpośrednich elementów potomnych elementu:
źródło
Math.random().toString(36).substr(2, 10)
wyprodukowania tego samego tokena więcej niż raz.any dupe would need to also be a child of the same parent node
,id
atrybuty są szeroko dokumentu. Masz rację, szanse są nadal znikome, ale dziękuję za wybranie dobrej drogi i dodanie tego licznika :)jeśli wiesz na pewno, że element jest unikalny (na przykład Twoja sprawa z identyfikatorem):
Aby uzyskać bardziej „globalne” rozwiązanie: (użyj podkładki matchSelector )
gdzie
elm
jest twój element nadrzędny isel
jest twoim selektorem. Może być również całkowicie wykorzystany jako prototyp.źródło
matchesSelector
nieprefiksowanego (co nie działa nawet w najnowszej wersji Chrome), zanieczyszcza globalną przestrzeń nazw (ret nie został zadeklarowany), nie zwraca NodeList, jak oczekuje się od querySelectorMethods. Nie sądzę, żeby to było dobre rozwiązanie, stąd głosy przeciw.Poniższe rozwiązanie różni się od dotychczas proponowanych i działa u mnie.
Powodem jest to, że najpierw wybierasz wszystkie pasujące dzieci, a następnie odfiltrowujesz te, które nie są bezpośrednimi dziećmi. Dziecko jest bezpośrednim dzieckiem, jeśli nie ma pasującego rodzica z tym samym selektorem.
HTH!
źródło
Stworzyłem funkcję, która poradzi sobie z tą sytuacją, pomyślałem, że się nią podzielę.
Zasadniczo to, co robisz, to generowanie losowego ciągu (funkcja randomString jest tutaj zaimportowanym modułem npm, ale możesz stworzyć własny), a następnie używając tego losowego ciągu, aby zagwarantować, że otrzymasz element, którego oczekujesz w selektorze. Następnie możesz swobodnie korzystać z
>
późniejszego.Powodem, dla którego nie używam atrybutu id, jest to, że atrybut id może już być używany i nie chcę go zastępować.
źródło
Cóż, możemy łatwo uzyskać wszystkie bezpośrednie elementy potomne elementu, używając
childNodes
i możemy wybrać przodków z określoną klasąquerySelectorAll
, więc nietrudno sobie wyobrazić, że moglibyśmy stworzyć nową funkcję, która pobiera oba i porównuje je.Uwaga: to zwróci tablicę węzłów, a nie listę węzłów.
Stosowanie
źródło
Chciałbym dodać, że można rozszerzyć kompatybilność : scope, po prostu przypisując atrybut tymczasowy do bieżącego węzła.
źródło
Poszedłbym z
źródło
Po prostu robię to, nawet nie próbując. Czy to zadziała?
Spróbuj, może to działa, a może nie. Apolovies, ale nie jestem teraz na komputerze, aby to wypróbować (odpowiadając z mojego iPhone'a).
źródło