ฉันมีฟังก์ชั่นเหมือน jquery:
function(elem) {
return $('> someselector', elem);
};
คำถามคือฉันจะทำเช่นเดียวกันกับquerySelector()
?
ปัญหาคือ>
ตัวเลือกในquerySelector()
ต้องระบุพาเรนต์อย่างชัดเจน มีวิธีแก้ปัญหาใด ๆ หรือไม่?
ฉันมีฟังก์ชั่นเหมือน jquery:
function(elem) {
return $('> someselector', elem);
};
คำถามคือฉันจะทำเช่นเดียวกันกับquerySelector()
?
ปัญหาคือ>
ตัวเลือกในquerySelector()
ต้องระบุพาเรนต์อย่างชัดเจน มีวิธีแก้ปัญหาใด ๆ หรือไม่?
คำตอบ:
แม้ว่ามันจะไม่ได้คำตอบที่เต็มคุณควรจับตามองในv.2 API W3C ตัวเลือกที่มีอยู่แล้วในเบราว์เซอร์มากที่สุดทั้งสก์ท็อปและโทรศัพท์มือถือยกเว้น IE (ขอบดูเหมือนว่าจะสนับสนุน): ดูรายการการสนับสนุนอย่างเต็มที่
function(elem) {
return elem.querySelectorAll(':scope > someselector');
};
:scope
ยังคงระบุที่drafts.csswg.org/selectors-4/#the-scope-pseudo จนถึงตอนนี้เป็นเพียง<style scoped>
แอตทริบิวต์ที่ถูกลบออกไป ไม่ชัดเจนว่าจะนำไปสู่การ:scope
ถูกลบหรือไม่ (เนื่องจาก<style scoped>
เป็นกรณีการใช้งานที่สำคัญสำหรับ:scope
)
คุณทำไม่ได้ ไม่มีตัวเลือกที่จะจำลองจุดเริ่มต้นของคุณ
วิธีที่ jQuery ทำ (มากขึ้นเนื่องจากวิธีการqsa
ทำงานที่ไม่เป็นที่ชื่นชอบของพวกเขา) คือพวกเขาตรวจสอบว่าelem
มี ID หรือไม่และถ้าไม่พวกเขาจะเพิ่ม ID ชั่วคราวจากนั้นสร้างสตริงตัวเลือกแบบเต็ม
โดยทั่วไปคุณจะทำ:
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 = '';
}
นี่ไม่ใช่โค้ด jQuery อย่างแน่นอน แต่จากสิ่งที่ฉันจำได้มันคือสิ่งที่พวกเขาทำ ไม่ใช่แค่ในสถานการณ์นี้ แต่ในสถานการณ์ใด ๆ ที่คุณกำลังเรียกใช้ตัวเลือกจากบริบทขององค์ประกอบที่ซ้อนกัน
ตามที่avetiskได้กล่าวถึง Selectors API 2 ใช้:scope
ตัวเลือกหลอก
เพื่อให้ทำงานได้ในทุกเบราว์เซอร์ (ที่รองรับquerySelector
) นี่คือ 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);
node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');
ด้วยเหตุผลทางประวัติศาสตร์วิธีแก้ปัญหาก่อนหน้าของฉัน
ขึ้นอยู่กับคำตอบทั้งหมด
// 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);
}
};
การใช้งาน
elem.find('> a');
Date.now()
ไม่รองรับเบราว์เซอร์รุ่นเก่าและสามารถแทนที่ด้วยnew Date().getTime()
หากคุณต้องการค้นหาลูกโดยตรงในที่สุด (ไม่ใช่เช่น> div > span
) คุณสามารถลองElement.matches () :
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>
เรียกร้อง
โดยส่วนตัวแล้วฉันจะรับคำตอบจาก patrick dw และ +1 คำตอบของเขาคำตอบของฉันคือการแสวงหาทางเลือกอื่น ฉันไม่คิดว่ามันสมควรได้รับการโหวตลดลง
นี่คือความพยายามของฉัน:
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];
}
}
querySelector
ซึ่งหมายความว่า:eq()
ไม่สามารถใช้งานได้ แม้ว่าจะทำได้ แต่ตัวเลือกของคุณจะส่งคืนองค์ประกอบที่มี:eq()
ลักษณะปรากฏบนหน้าเว็บไม่ใช่:eq()
ไปที่ดัชนีของพาเรนต์ (ซึ่งเป็นที่ที่คุณได้รับidx
)
elem
อยู่ที่ดัชนี 4 แต่มีพี่น้องก่อนหน้านี้ที่มีความแตกต่างกันtagName
แต่มีการซ้อนอยู่ภายในองค์ประกอบที่มีการจับคู่tagName
องค์ประกอบที่ซ้อนกันจะรวมอยู่ในผลลัพธ์ก่อนที่คุณจะกำหนดเป้าหมายอีกครั้ง ดัชนี นี่คือตัวอย่าง
$('> someselector', elem);
; o)
หากคุณทราบชื่อแท็กขององค์ประกอบที่คุณกำลังมองหาคุณสามารถใช้ในตัวเลือกเพื่อให้บรรลุสิ่งที่คุณต้องการ
ตัวอย่างเช่นถ้าคุณมี<select>
ที่มี<option>
และ<optgroups>
และคุณต้องการเฉพาะ<option>
ของที่เป็นลูกของมันทันที, ไม่ได้คนที่อยู่ภายใน<optgoups>
:
<select>
<option>iPhone</option>
<optgroup>
<option>Nokia</option>
<option>Blackberry</option>
</optgroup>
</select>
ดังนั้นเมื่อมีการอ้างอิงถึงองค์ประกอบที่เลือกคุณจึงสามารถรับลูกได้ทันทีเช่นนี้:
selectElement.querySelectorAll('select > option')
ดูเหมือนว่าจะใช้งานได้ใน Chrome, Safari และ Firefox แต่ไม่ได้ทดสอบใน IE = /
<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 จะถูกเลือก!
<select>
องค์ประกอบในพ่อแม่เดียวกัน
ต่อไปนี้เป็นง่ายวิธีการทั่วไปสำหรับการเรียกใช้แบบสอบถามเลือก CSS ใด ๆ ที่มากกว่าเด็กโดยตรงเท่านั้น - มันยังบัญชีสำหรับการค้นหารวมเช่น"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"]');
มีความเป็นแบบสอบถามญาติ lib ซึ่งเป็นทดแทนที่มีประโยชน์มากสำหรับแบบสอบถามเลือก เป็นตัวเลือกเด็ก polyfills '> *'
และ:scope
(รวม IE8) รวมทั้ง:root
ตัวเลือกปกติ นอกจากนี้ยังจะให้ pseudos ญาติบางพิเศษเช่น:closest
, :parent
, :prev
, :next
เพียงในกรณีที่
ที่ได้ผลสำหรับฉัน:
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);
};
คุณจะต้องผ่าน @this keywork ก่อน> เมื่อคุณต้องการค้นหาเด็กในทันที
ตรวจสอบว่าองค์ประกอบมี id อื่นหรือไม่เพิ่ม id แบบสุ่มและทำการค้นหาตามมัน
function(elem) {
if(!elem.id)
elem.id = Math.random().toString(36).substr(2, 10);
return elem.querySelectorAll(elem.id + ' > someselector');
};
จะทำสิ่งเดียวกันกับ
$("> someselector",$(elem))