प्रत्यक्ष बच्चों को पुनः प्राप्त करने के लिए querySelectorAll का उपयोग करना


119

मैं ऐसा करने में सक्षम हूं:

<div id="myDiv">
   <div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");

यही है, मैं उस myDivतत्व के सभी प्रत्यक्ष बच्चों को सफलतापूर्वक पुनर्प्राप्त कर सकता हूं जिनके पास कक्षा है .foo

समस्या यह है कि यह मुझे परेशान करता है कि मुझे #myDivचयनकर्ता में शामिल करना होगा , क्योंकि मैं myDivतत्व पर क्वेरी चला रहा हूं (इसलिए यह स्पष्ट रूप से बेमानी है)।

मैं #myDivबंद छोड़ने में सक्षम होना चाहिए , लेकिन तब चयनकर्ता कानूनी वाक्यविन्यास नहीं है क्योंकि यह एक के साथ शुरू होता है >

क्या किसी को पता है कि कैसे चयनकर्ता लिखना है जो उस तत्व के सीधे बच्चों को प्राप्त करता है जिस पर चयनकर्ता चल रहा है?



क्या किसी भी उत्तर ने आपकी ज़रूरत पूरी नहीं की? कृपया प्रतिक्रिया दें या उत्तर चुनें।
रैंडी हॉल

@mattsh - मैंने आपकी ज़रूरत के लिए एक बेहतर (IMO) उत्तर जोड़ा है, इसे देखें!
csuwldcat

जवाबों:


85

अच्छा प्रश्न। जिस समय यह पूछा गया था, "कॉम्बीनेटर रूटेड क्वेश्चन " करने के लिए एक सार्वभौमिक रूप से लागू किया गया तरीका (जैसा कि जॉन रेज ने उन्हें बताया था) ) मौजूद नहीं था।

अब : स्कोप छद्म श्रेणी शुरू की गई है। यह एज या IE के [प्री-क्रोमिनम] संस्करणों पर समर्थित नहीं है , लेकिन कुछ साल पहले से ही सफारी द्वारा समर्थित है। इसका उपयोग करते हुए, आपका कोड बन सकता है:

let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");

ध्यान दें कि कुछ मामलों में आप .querySelectorAllअन्य पुराने जमाने के DOM API फीचर को छोड़ और उपयोग कर सकते हैं । उदाहरण के लिए, myDiv.querySelectorAll(":scope > *")आप के बजाय बस लिख सकता हैmyDiv.children , उदाहरण के लिए।

अन्यथा यदि आप अभी तक भरोसा नहीं कर सकते हैं :scope, तो मैं अधिक कस्टम फ़िल्टर तर्क (जैसे कि myDiv.getElementsByClassName("foo")किसका पता लगाएं .parentNode === myDiv) को जोड़े बिना आपकी स्थिति को संभालने का एक और तरीका नहीं सोच सकता , और जाहिर है कि आदर्श नहीं है यदि आप एक कोड पथ का समर्थन करने की कोशिश कर रहे हैं जो वास्तव में बस इनपुट के रूप में एक मनमाना चयनकर्ता स्ट्रिंग और आउटपुट के रूप में मैचों की एक सूची लेना चाहता है! लेकिन अगर मेरी तरह आप यह सवाल पूछते हुए समाप्त हो गए, क्योंकि आप यह सोचकर फंस गए कि "आप सभी एक हथौड़ा थे" यह मत भूलो कि डोम ऑफ़र भी कई अन्य उपकरण हैं।


3
myDiv.getElementsByClassName("foo")यह वैसा नहीं है myDiv.querySelectorAll("> .foo"), यह अधिक पसंद है myDiv.querySelectorAll(".foo")(जो वास्तव में इस तरह से काम करता है) कि यह सभी वंशजों .fooको सिर्फ बच्चों के विपरीत पाता है ।
BoltClock

अरे परेशान हो! जिससे मेरा मतलब है: तुम बिलकुल ठीक कह रहे हो। मैंने अपना उत्तर अपडेट करके यह स्पष्ट कर दिया है कि यह ओपी के मामले में बहुत अच्छा नहीं है।
natevw

लिंक के लिए धन्यवाद (जो निश्चित रूप से इसका उत्तर देता है), और शब्दावली को जोड़ने के लिए धन्यवाद "कॉम्बीनेटर निहित प्रश्न"।
मत्तश

1
जॉन रेजिग "कॉम्बीनेटर-रूटेड क्वेश्चन" कहते हैं, चयनकर्ता 4 अब उन्हें रिश्तेदार चयनकर्ता कहते हैं ।
बोल्टकॉक

@Andrew Scoped स्टाइलशीट (यानी <style scoped>) :scopeका इस उत्तर में वर्णित छद्म चयनकर्ता से कोई लेना -देना नहीं है।
natevw

124

क्या किसी को पता है कि कैसे चयनकर्ता लिखना है जो उस तत्व के सीधे बच्चों को प्राप्त करता है जिस पर चयनकर्ता चल रहा है?

चयनकर्ता को लिखने का सही तरीका जो वर्तमान तत्व के लिए "जड़" है, का उपयोग करना है :scope

var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");

तथापि, ब्राउज़र समर्थन सीमित है और यदि आप इसका उपयोग करना चाहते हैं तो आपको एक शिम की आवश्यकता होगी। मैंने इस उद्देश्य के लिए scopedQuerySelectorShim का निर्माण किया ।


3
यह ध्यान देने योग्य है कि :scopeवर्तमान में कल्पना एक "वर्किंग ड्राफ्ट" है और इसलिए परिवर्तन के अधीन है। इसकी संभावना है कि यह अभी भी इस तरह से काम करेगा यदि / जब इसे अपनाया जाता है, लेकिन यह कहने के लिए थोड़ा जल्दी है कि यह मेरी राय में करने का "सही तरीका" है।
Zach Lysobey

2
ऐसा लगता है कि इस बीच का
चित्रण

1
3 साल बाद और आप मेरे ग्लूटस मैक्सिमस को बचाते हैं!
मेहरद

5
@ एड्रियन Moisa:: गुंजाइश कहीं भी पदावनत नहीं किया गया है। आप इसे स्कॉप्ड विशेषता के साथ मिला सकते हैं।
BoltClock

6

यहाँ एक लचीला तरीका है, जो कि वेनिला JS में लिखा गया है, जो आपको एक तत्व के केवल प्रत्यक्ष बच्चों पर CSS चयनकर्ता क्वेरी चलाने की अनुमति देता है:

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;
}

मेरा सुझाव है कि आप अपने द्वारा बनाए गए आईडी में किसी प्रकार का टाइमस्टैम्प या काउंटर जोड़ें। एक Math.random().toString(36).substr(2, 10)से अधिक बार एक ही टोकन का उत्पादन करने के लिए एक गैर-शून्य (यद्यपि छोटा) संभावना है ।
Frédéric Hamidi

मुझे यकीन नहीं है कि दोहराने की संभावना को देखते हुए यह कैसे संभव है कि माइनसक्यूल हो, आईडी केवल अस्थायी रूप से एक मिलीसेकंड के एक अंश के लिए लागू की जाती है, और किसी भी डूप को एक ही मूल नोड का बच्चा होने की आवश्यकता होगी - मूल रूप से - संभावनाएँ खगोलीय हैं। बावजूद, एक काउंटर जोड़ना ठीक लगता है।
19w को 1929 में csuwldcat

यह निश्चित नहीं है कि आप क्या मतलब है any dupe would need to also be a child of the same parent node, idविशेषताएँ दस्तावेज़-व्यापी हैं। आप सही कह रहे हैं कि ऑड्स अभी भी काफी नगण्य हैं, लेकिन हाई रोड लेने और उस काउंटर को जोड़ने के लिए धन्यवाद :)
Frédéric Hamidi

8
जावास्क्रिप्ट को समानांतर में निष्पादित नहीं किया गया है, इसलिए संभावना वास्तव में शून्य है।
WGH

1
@ वाह, मैं इस पर विश्वास नहीं कर सकता, मैं बिल्कुल स्तब्ध हूं कि मैं इस तरह के एक सरल बिंदु पर मस्तिष्क का मस्सा करूंगा (मैं मोज़िला में काम करता हूं और इस तथ्य को अक्सर
सुनता हूं

5

यदि आपको पता है कि तत्व अद्वितीय है (जैसे कि आईडी के साथ आपका मामला):

myDiv.parentElement.querySelectorAll("#myDiv > .foo");

अधिक "वैश्विक" समाधान के लिए: ( माचिस की तीली का उपयोग करें )

function getDirectChildren(elm, sel){
    var ret = [], i = 0, l = elm.childNodes.length;
    for (var i; i < l; ++i){
        if (elm.childNodes[i].matchesSelector(sel)){
            ret.push(elm.childNodes[i]);
        }
    }
    return ret;
}

elmआपका मूल तत्व कहां है, और selआपका चयनकर्ता है। पूरी तरह से एक प्रोटोटाइप के रूप में भी इस्तेमाल किया जा सकता है।


@lazd जो प्रश्न का हिस्सा नहीं है।
रैंडी हॉल

आपका उत्तर "वैश्विक" समाधान नहीं है। इसकी विशिष्ट सीमाएँ हैं जिन्हें नोट किया जाना चाहिए, इसलिए मेरी टिप्पणी।
लाज्ड

@lazd जो पूछे गए सवाल का जवाब देता है। तो डाउन वोट क्यों? या क्या आपने सिर्फ साल के उत्तर पर डाउन-वोट के सेकंड के भीतर टिप्पणी करने के लिए किया था?
रैंडी हॉल

समाधान में matchesSelectorउपसर्ग का उपयोग होता है (जो क्रोम के नवीनतम संस्करण में भी काम नहीं करता है), यह वैश्विक नामस्थान (रिट घोषित नहीं किया गया था) को प्रदूषित करता है, यह एक NodeList को नहीं लौटाता है जैसे कि क्वेरीसेलरमैथोड्स से अपेक्षित है। मुझे नहीं लगता कि यह एक अच्छा समाधान है, इसलिए नीचे की ओर।
लाज्ड

@lazd - मूल प्रश्न अप्रयुक्त फ़ंक्शन और वैश्विक नामस्थान का उपयोग करता है। यह दिए गए प्रश्न के लिए पूरी तरह से ठीक है। यदि आपको नहीं लगता कि यह एक अच्छा समाधान है, तो इसका उपयोग न करें, या एक संपादन का सुझाव दें। यदि यह कार्यात्मक रूप से गलत है या स्पैम है, तो डाउनवोट पर विचार करें।
रैंडी हॉल

2

निम्नलिखित समाधान अभी तक प्रस्तावित लोगों के लिए अलग है, और मेरे लिए काम करता है।

तर्क यह है कि आप पहले सभी मिलान वाले बच्चों का चयन करते हैं, और फिर उन बच्चों को फ़िल्टर करते हैं जो सीधे बच्चे नहीं हैं। एक बच्चा एक सीधा बच्चा है यदि उसके पास एक ही चयनकर्ता के साथ मेल खाने वाला माता-पिता नहीं है।

function queryDirectChildren(parent, selector) {
    const nodes = parent.querySelectorAll(selector);
    const filteredNodes = [].slice.call(nodes).filter(n => 
        n.parentNode.closest(selector) === parent.closest(selector)
    );
    return filteredNodes;
}

HTH!


मुझे इसकी संक्षिप्तता और दृष्टिकोण की सादगी पसंद है, हालांकि यह बड़े पेड़ों और उच्च लालची चयनकर्ताओं के साथ उच्च आवृत्ति पर बुलाया जाता है, तो यह सबसे अच्छा प्रदर्शन नहीं करेगा।
ब्रेनन्यूंग

1

मैंने इस स्थिति को संभालने के लिए एक फ़ंक्शन बनाया, सोचा कि मैं इसे साझा करूंगा।

getDirectDecendent(elem, selector, all){
    const tempID = randomString(10) //use your randomString function here.
    elem.dataset.tempid = tempID;

    let returnObj;
    if(all)
        returnObj = elem.parentElement.querySelectorAll(`[data-tempid="${tempID}"] > ${selector}`);
    else
        returnObj = elem.parentElement.querySelector(`[data-tempid="${tempID}"] > ${selector}`);

    elem.dataset.tempid = '';
    return returnObj;
}

संक्षेप में, आप जो कर रहे हैं वह एक रैंडम-स्ट्रिंग (रैंडम स्ट्रींग फंक्शन है) यहाँ एक आयातित npm मॉड्यूल है, लेकिन आप अपना खुद का बना सकते हैं।) फिर उस रैंडम स्ट्रिंग का उपयोग करके यह गारंटी देने के लिए कि आप उस तत्व को प्राप्त कर रहे हैं जिसका आप चयनकर्ता में अपेक्षा कर रहे हैं। तो आप का उपयोग करने के लिए स्वतंत्र हैं> बाद ।

आईडी विशेषता का उपयोग नहीं करने का कारण यह है कि आईडी विशेषता का उपयोग पहले से ही किया जा सकता है और मैं इसे ओवरराइड नहीं करना चाहता।


0

खैर हम आसानी से एक तत्व के सभी प्रत्यक्ष बच्चों को प्राप्त कर सकते हैं childNodesऔर हम एक विशिष्ट वर्ग के साथ पूर्वजों का चयन कर सकते हैं querySelectorAll, इसलिए यह कल्पना करना मुश्किल नहीं है कि हम एक नया फ़ंक्शन बना सकते हैं जो दोनों को प्राप्त करता है और दोनों की तुलना करता है।

HTMLElement.prototype.queryDirectChildren = function(selector){
  var direct = [].slice.call(this.directNodes || []); // Cast to Array
  var queried = [].slice.call(this.querySelectorAll(selector) || []); // Cast to Array
  var both = [];
  // I choose to loop through the direct children because it is guaranteed to be smaller
  for(var i=0; i<direct.length; i++){
    if(queried.indexOf(direct[i])){
      both.push(direct[i]);
    }
  }
  return both;
}

नोट: यह एक नोड का एरियर लौटाएगा, न कि कोई नोडलिस्ट।

प्रयोग

 document.getElementById("myDiv").queryDirectChildren(".foo");

0

मैं यह जोड़ना चाहूंगा कि आप वर्तमान नोड के लिए एक अस्थायी विशेषता निर्दिष्ट करके : की गुंजाइश का विस्तार कर सकते हैं ।

let node = [...];
let result;

node.setAttribute("foo", "");
result = window.document.querySelectorAll("[foo] > .bar");
// And, of course, you can also use other combinators.
result = window.document.querySelectorAll("[foo] + .bar");
result = window.document.querySelectorAll("[foo] ~ .bar");
node.removeAttribute("foo");


-2

मैं इसे बिना कोशिश किए भी कर रहा हूं। क्या यह काम करेगा?

myDiv = getElementById("myDiv");
myDiv.querySelectorAll(this.id + " > .foo");

यह एक कोशिश दे, शायद यह काम करता है शायद नहीं। Apolovies, लेकिन मैं इसे (मेरे iPhone से जवाब) आजमाने के लिए अब कंप्यूटर पर नहीं हूं।


3
QSA को उस तत्व पर बुलाया जाता है, जिस पर उसे कॉल किया जा रहा है, इसलिए यह myDiv के अंदर एक अन्य तत्व की तलाश करेगा, जिसमें myDiv के समान ID है, फिर .foo के साथ उसके बच्चे। आप 'document.querySelectorAll (' # # + myDiv.id + '> .foo') जैसा कुछ कर सकते हैं;
संभवत:
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.