querySelector arama yakın alt


102

Jquery benzeri bir işlevim var:

function(elem) {
    return $('> someselector', elem);
};

Soru aynı şeyi nasıl yapabilirim querySelector()?

Sorun, >seçicinin querySelector()ebeveynin açıkça belirtilmesini gerektirmesidir. Herhangi bir çözüm var mı?


Sizin için daha işe yarayabilecek bir cevap ekledim, haberim olsun;)
csuwldcat

Yanıtlar:


128

Tam bir cevap olmasa da , IE dışında hem masaüstü hem de mobil çoğu tarayıcıda zaten mevcut olan W3C Selector API v.2'ye bir göz atmalısınız (Edge destekliyor gibi görünüyor): tam destek listesine bakın .

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};

13
Bu doğru cevap. Ancak, tarayıcı desteği sınırlıdır ve kullanmak istiyorsanız bir şime ihtiyacınız olacaktır. Ben inşa scopedQuerySelectorShim bu amaçla.
lazd

3
: Kapsam özniteliği mevcut belirtimden kaldırılmıştır .
tobi

7
Aslında, :scopehala drafts.csswg.org/selectors-4/#the-scope-pseudo adresinde belirtilmektedir . Şimdiye kadar yalnızca <style scoped>kaldırılan öznitelik; Bunun :scopekaldırılmasına da yol açıp açmayacağı belli değil (çünkü <style scoped>önemli bir kullanım durumuydu :scope).
John Mellor

2
Ne sürpriz: yalnızca Edge bunu desteklemiyor
Xenos

33

Yapamazsın. Başlangıç ​​noktanızı simüle edecek bir seçici yok.

JQuery'nin bunu yapma şekli (daha qsaçok, onların beğenisine uygun olmayan bir davranış şekli nedeniyle ), elembir kimliği olup olmadığını kontrol etmeleri ve yoksa, geçici olarak bir kimlik eklemeleri ve ardından tam bir seçici dizesi oluşturmalarıdır.

Temelde yaparsın:

var sel = '> someselector';
var hadId = true;
if( !elem.id ) {
    hadID = false;
    elem.id = 'some_unique_value';
}

sel = '#' + elem.id + sel;

var result = document.querySelectorAll( sel );

if( !hadId ) {
    elem.id = '';
}

Bu kesinlikle jQuery kodu değil, ama hatırladığım kadarıyla temelde yaptıkları şey bu. Sadece bu durumda değil, aynı zamanda iç içe yerleştirilmiş bir öğe bağlamından bir seçici çalıştırdığınız her durumda.

Sizzle için kaynak kodu


1
Yazma sırasında düzeltin, ancak güncellenmiş bir yöntem için @ avetisk'in cevabına bakın.
lazd

25

Eksiksiz: kapsam polyfill

Olarak avetisk olan bahsedilen Seçiciler API 2 kullanımları :scopeyalancı seçiciye.
Bunun tüm tarayıcılarda (destekleyen querySelector) çalışmasını sağlamak için işte polyfill

(function(doc, proto) {
  try { // check if browser supports :scope natively
    doc.querySelector(':scope body');
  } catch (err) { // polyfill native methods if it doesn't
    ['querySelector', 'querySelectorAll'].forEach(function(method) {
      var nativ = proto[method];
      proto[method] = function(selectors) {
        if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope
          var id = this.id; // remember current element id
          this.id = 'ID_' + Date.now(); // assign new unique id
          selectors = selectors.replace(/((^|,)\s*):scope/g, '$1#' + this.id); // replace :scope with #ID
          var result = doc[method](selectors);
          this.id = id; // restore previous id
          return result;
        } else {
          return nativ.call(this, selectors); // use native code for other selectors
        }
      }
    });
  }
})(window.document, Element.prototype);

Kullanım

node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');

Tarihsel nedenlerden dolayı, önceki çözümüm

Tüm cevaplara göre

// Caution! Prototype extending
Node.prototype.find = function(selector) {
    if (/(^\s*|,\s*)>/.test(selector)) {
        if (!this.id) {
            this.id = 'ID_' + new Date().getTime();
            var removeId = true;
        }
        selector = selector.replace(/(^\s*|,\s*)>/g, '$1#' + this.id + ' >');
        var result = document.querySelectorAll(selector);
        if (removeId) {
            this.id = null;
        }
        return result;
    } else {
        return this.querySelectorAll(selector);
    }
};

Kullanım

elem.find('> a');

Date.now()eski tarayıcılar tarafından desteklenmez ve şu şekilde değiştirilebilirnew Date().getTime()
Christophe

6

Sonunda doğrudan çocukları bulmak istiyorsanız (örneğin değil > div > span), Element.matches () 'i deneyebilirsiniz :

const elem = document.body
const elems = [...elem.children].filter(e => e.matches('b'))

console.log(elems)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>


5

İDDİA

Ben şahsen cevabı patrick dw'den alırım ve cevabını +1 alırdım, cevabım alternatif çözüm aramaktır. Olumsuz oyu hak ettiğini düşünmüyorum.

İşte girişimim:

function q(elem){
    var nodes = elem.querySelectorAll('someSeletor');
    console.log(nodes);
    for(var i = 0; i < nodes.length; i++){
        if(nodes[i].parentNode === elem) return nodes[i];
    }
}

bkz. http://jsfiddle.net/Lgaw5/8/


1
Bununla ilgili birkaç sorun var. @ memnun, bununla çalışmasını istiyor querySelector, bu :eq()da kullanılamayacağı anlamına geliyor . Yapabilse bile, seçiciniz , üst öğesinin dizinine :eq()değil, sayfadaki görünümüne dönecektir (bu öğeyi aldığınız :eq()yer burasıdır idx).
user113716

Eq () & querySelector hakkında +1. Ve $ (elem) .parent () bağlamını eklemeliyim.
Liangliang Zheng

Ne yazık ki bu da işe yaramayacak. Seçici, üst öğe bağlamından çalıştığında, en soldaki çocukla başlar ve ne kadar derinlemesine iç içe geçmiş olursa olsun eşleşen tüm öğeleri bulur, devam eder. Diyelim ki, elemdizin 4'tedir tagName, ancak farklı olan bir önceki kardeş var , ancak bunun içinde eşleşen bir öğe tagNameyuvalanmış, bu yuvalanmış öğe, hedeflediğinizden önce sonuçlara dahil edilecek ve yine İçerik. İşte bir örnek
user113716

... her neyse, nihayetinde yaptığınız şey, sorudaki kodun daha karmaşık bir versiyonu ve işe yarıyor. $('> someselector', elem);; o)
user113716

Evet ama bu tek artımı sabit kodlamanız gerekiyordu. Bu, bununla ilgili önceden bilgi gerektirir. Başka bir benzer öğe eklersem, tekrar bozulur. ; o) jsfiddle.net/Lgaw5/3
user113716

5

Baktığınız öğenin etiket adını biliyorsanız, istediğiniz şeyi elde etmek için bunu seçicide kullanabilirsiniz.

Örneğin bir varsa <select>vardır <option>s ve <optgroups>ve yalnızca istediğiniz <option>onun hemen çocuk, içeride olanlar değil s <optgoups>:

<select>
  <option>iPhone</option>
  <optgroup>
    <option>Nokia</option>
    <option>Blackberry</option>
  </optgroup>
</select>

Dolayısıyla, seçili öğeye bir referans alarak, şaşırtıcı bir şekilde, çocuklarını şu şekilde elde edebilirsiniz:

selectElement.querySelectorAll('select > option')

Chrome, Safari ve Firefox'ta çalışıyor gibi görünüyor, ancak IE'lerde test edilmedi. = /


9
Uyarı: Bu cevap aslında kapsamı sınırlamaz. Desen daha derin yuva seviyesinde tekrarlanırsa, doğrudan çocuk olmasa bile yine de seçilecektir. <ul id="start"> <li>A</li> <li> <ul> <li>b</li> <li>c</li> </ul> </li> </ul> var result = document.getElementById('start').querySelectorAll('ul>li'); -> 4 li öğesinin tümü seçilecektir!
Risord

1
Tanrı korusun <select>aynı ebeveynde iki unsur vardı .
Tomáš Zato - Monica'yı yeniden etkinleştir

2

Aşağıdakiler, herhangi bir CSS seçici sorgusunu yalnızca doğrudan alt öğeler üzerinde çalıştırmak için basitleştirilmiş, genel bir yöntemdir - aynı zamanda aşağıdakiler gibi birleşik sorguları da hesaba katar "foo[bar], baz.boo":

var count = 0;
function queryChildren(element, selector) {
  var id = element.id,
      guid = element.id = id || 'query_children_' + count++,
      attr = '#' + guid + ' > ',
      selector = attr + (selector + '').replace(',', ',' + attr, 'g');
  var result = element.parentNode.querySelectorAll(selector);
  if (!id) element.removeAttribute('id');
  return result;
}


*** Example Use ***

queryChildren(someElement, '.foo, .bar[xyz="123"]');

2

Bir var sorgu göreli için oldukça kullanışlı yerine geçer lib, sorgu-seçicinin . Çocuk seçiciyi '> *'ve :scope(IE8 dahil) çoklu doldurur ve :rootseçiciyi normalleştirir . Ayrıca gibi bazı özel nispi pseudos sağlar :closest, :parent, :prev, :next, her ihtimale karşı.


1

Benim için çalıştı:

Node.prototype.search = function(selector)
{
    if (selector.indexOf('@this') != -1)
    {
        if (!this.id)
            this.id = "ID" + new Date().getTime(); 
        while (selector.indexOf('@this') != -1)
            selector = selector.replace('@this', '#' + this.id);
        return document.querySelectorAll(selector);
    } else 
        return this.querySelectorAll(selector);
};

Çocukları hemen aramak istediğinizde, @this anahtar işini> öğesinden önce iletmeniz gerekir.


Şu anda kabul edilen cevapla aynı görünüyor ... Btw, tuhaf "@bu" sözdiziminin anlamı nedir? Neden regexp ile ">" için test etmiyorsunuz?
2013

0

öğenin kimliği olup olmadığını kontrol edin, başka bir rastgele kimlik ekleyin ve buna göre arama yapın

function(elem) {
      if(!elem.id)
          elem.id = Math.random().toString(36).substr(2, 10);
      return elem.querySelectorAll(elem.id + ' > someselector');
    };

aynı şeyi yapacak

$("> someselector",$(elem))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.