มีการพัฒนาแนวปฏิบัติที่ดีที่สุดเกี่ยวกับการใช้setAttributeแทนเครื่องหมายจุด dot ( .) หรือไม่?
เช่น:
myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");
หรือ
myObj.className = "nameOfClass";
myObj.id = "someID";
มีการพัฒนาแนวปฏิบัติที่ดีที่สุดเกี่ยวกับการใช้setAttributeแทนเครื่องหมายจุด dot ( .) หรือไม่?
เช่น:
myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");
หรือ
myObj.className = "nameOfClass";
myObj.id = "someID";
คำตอบ:
คุณควรใช้.attributeแบบฟอร์มโดยตรง(แต่เห็นลิงค์ quirksmode ด้านล่าง) หากคุณต้องการเข้าถึงแบบเป็นโปรแกรมใน JavaScript ควรจัดการแอตทริบิวต์ประเภทต่างๆ (คิดว่า "onload") อย่างถูกต้อง
ใช้getAttribute/ setAttributeเมื่อคุณต้องการจัดการกับ DOM เหมือนเดิม (เช่นข้อความตัวอักษรเท่านั้น) เบราว์เซอร์ที่แตกต่างกันสร้างความสับสนให้ทั้งสอง ดูโหมด Quirks: แอตทริบิวต์ (ใน)
จากJavascript: The Definitive Guideจะอธิบายสิ่งต่าง ๆ มันตั้งข้อสังเกตว่าวัตถุHTMLElementของเอกสาร HTML กำหนดคุณสมบัติ JS ที่สอดคล้องกับคุณลักษณะ HTML มาตรฐานทั้งหมด
ดังนั้นคุณจะต้องใช้setAttributeสำหรับแอตทริบิวต์ที่ไม่ได้มาตรฐานเท่านั้น
ตัวอย่าง:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborderไม่ได้ถูกกำหนดดังนั้นคุณต้อง getAttribute เพื่อรับค่ากลับมา
frameBorderโดยตรง แต่ให้สังเกตว่าตัวพิมพ์ใหญ่ มีคนคิดว่ามันเป็นความคิดที่ดีที่จะ camelCase เทียบเท่า JavaScript ของแอตทริบิวต์ HTML ฉันไม่สามารถหาข้อมูลจำเพาะใด ๆ สำหรับเรื่องนี้ได้ แต่เน็ตดูเหมือนจะยอมรับว่าเป็นเรื่องเฉพาะ 12 เรื่อง (สำหรับ HTML 4 อย่างน้อย) ดูตัวอย่างโพสต์ต่อไปนี้: drupal.org/node/1420706#comment-6423420
usemapแอตทริบิวต์ไม่สามารถตั้งค่าการใช้สัญกรณ์จุดเมื่อมีการสร้างแผนที่แบบไดนามิกสำหรับภาพ มันต้องมีimg.setAttribute('usemap', "#MapName");คำตอบของคุณหมายความว่าusemap"ไม่ได้มาตรฐาน" หรือไม่?
ไม่มีคำตอบก่อนหน้านี้ที่สมบูรณ์และส่วนใหญ่ประกอบด้วยข้อมูลที่ผิด
การเข้าถึงแอตทริบิวต์ขององค์ประกอบ DOM ใน JavaScript มีสามวิธี ทั้งสามทำงานได้อย่างน่าเชื่อถือในเบราว์เซอร์สมัยใหม่ตราบใดที่คุณเข้าใจวิธีการใช้งาน
element.attributesองค์ประกอบที่มีคุณสมบัติคุณลักษณะที่ส่งกลับสดNamedNodeMapของattrวัตถุ ดัชนีของคอลเลกชันนี้อาจแตกต่างจากเบราว์เซอร์ ดังนั้นไม่รับประกันการสั่งซื้อ NamedNodeMapมีวิธีการเพิ่มและลบแอตทริบิวต์ ( getNamedItemและsetNamedItemตามลำดับ)
โปรดสังเกตว่าแม้ว่า XML จะคำนึงถึงขนาดตัวพิมพ์อย่างชัดเจน แต่ข้อมูลจำเพาะ DOM เรียกชื่อสตริงให้เป็นมาตรฐานดังนั้นชื่อที่ส่งผ่านgetNamedItemจะไม่ตรงตามตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก
var div = document.getElementsByTagName('div')[0];
//you can look up specific attributes
var classAttr = div.attributes.getNamedItem('CLASS');
document.write('attributes.getNamedItem() Name: ' + classAttr.name + ' Value: ' + classAttr.value + '<br>');
//you can enumerate all defined attributes
for(var i = 0; i < div.attributes.length; i++) {
var attr = div.attributes[i];
document.write('attributes[] Name: ' + attr.name + ' Value: ' + attr.value + '<br>');
}
//create custom attribute
var customAttr = document.createAttribute('customTest');
customAttr.value = '567';
div.attributes.setNamedItem(customAttr);
//retreive custom attribute
customAttr = div.attributes.getNamedItem('customTest');
document.write('attributes.getNamedItem() Name: ' + customAttr.name + ' Value: ' + customAttr.value + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.getAttribute&element.setAttributeวิธีการเหล่านี้มีอยู่โดยตรงบนElementโดยไม่จำเป็นต้องเข้าถึงattributesและวิธีการ แต่ทำหน้าที่เดียวกัน
โปรดสังเกตอีกครั้งว่าชื่อสตริงเป็นแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.getAttribute('class') + '<br>');
document.write('Name: ID Value: ' + div.getAttribute('ID') + '<br>');
document.write('Name: DATA-TEST Value: ' + div.getAttribute('DATA-TEST') + '<br>');
document.write('Name: nonStandard Value: ' + div.getAttribute('nonStandard') + '<br>');
//create custom attribute
div.setAttribute('customTest', '567');
//retreive custom attribute
document.write('Name: customTest Value: ' + div.getAttribute('customTest') + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.idคุณลักษณะมากมายสามารถเข้าถึงได้โดยใช้คุณสมบัติที่สะดวกสบายในวัตถุ DOM คุณลักษณะใดที่มีอยู่ขึ้นอยู่กับชนิดของโหนด DOM ไม่ใช่คุณลักษณะที่กำหนดไว้ใน HTML คุณสมบัติถูกกำหนดที่ใดที่หนึ่งในห่วงโซ่ต้นแบบของวัตถุ DOM ที่เป็นปัญหา คุณสมบัติเฉพาะที่กำหนดจะขึ้นอยู่กับประเภทขององค์ประกอบที่คุณกำลังเข้าถึง ตัวอย่างเช่นclassNameและidมีการกำหนดElementและมีอยู่ในโหนด DOM ทั้งหมดที่เป็นองค์ประกอบ (เช่นไม่ใช่ข้อความหรือโหนดความคิดเห็น) แต่valueแคบกว่า มันกำหนดไว้HTMLInputElementและอาจไม่มีอยู่ในองค์ประกอบอื่น ๆ
ขอให้สังเกตว่าคุณสมบัติ JavaScript เป็นกรณี ๆ ไป แม้ว่าคุณสมบัติส่วนใหญ่จะใช้ตัวพิมพ์เล็ก แต่บางตัวก็เป็น camelCase ดังนั้นโปรดตรวจสอบข้อมูลจำเพาะเพื่อให้แน่ใจเสมอ
"แผนภูมิ" นี้จับส่วนของต้นแบบลูกโซ่สำหรับวัตถุ DOM เหล่านี้ มันไม่ได้ใกล้จะเสร็จสมบูรณ์ แต่รวบรวมโครงสร้างโดยรวม
____________Node___________
| | |
Element Text Comment
| |
HTMLElement SVGElement
| |
HTMLInputElement HTMLSpanElement
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.className + '<br>');
document.write('Name: id Value: ' + div.id + '<br>');
document.write('Name: ID Value: ' + div.ID + '<br>'); //undefined
document.write('Name: data-test Value: ' + div.dataset.test + '<br>'); //.dataset is a special case
document.write('Name: nonStandard Value: ' + div.nonStandard + '<br>'); //undefined
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
Caveat: นี่คือคำอธิบายว่า HTML spec กำหนดและเบราว์เซอร์ที่ทันสมัยจัดการกับคุณลักษณะอย่างไร ฉันไม่ได้พยายามที่จะจัดการกับข้อ จำกัด ของเบราว์เซอร์โบราณที่เสียหาย หากคุณต้องการสนับสนุนเบราว์เซอร์รุ่นเก่านอกเหนือจากข้อมูลนี้คุณจะต้องทราบว่าเบราว์เซอร์ใดที่เสียหาย
กรณีหนึ่งที่ฉันพบว่าsetAttributeสิ่งที่จำเป็นคือเมื่อเปลี่ยนคุณลักษณะ ARIA เนื่องจากไม่มีคุณสมบัติที่สอดคล้องกัน ตัวอย่างเช่น
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
ไม่มีx.arialabelหรืออะไรทำนองนั้นดังนั้นคุณต้องใช้ setAttribute
แก้ไข: x [ "เพลงป้าย"] ไม่ทำงาน คุณต้องการ setAttribute จริงๆ
x.getAttribute('aria-label')
null
x["aria-label"] = "Test"
"Test"
x.getAttribute('aria-label')
null
x.setAttribute('aria-label', 'Test2')
undefined
x["aria-label"]
"Test"
x.getAttribute('aria-label')
"Test2"
คำตอบเหล่านี้ไม่ได้จริงๆที่อยู่ความสับสนระหว่างขนาดใหญ่ที่มีคุณสมบัติและคุณลักษณะ นอกจากนี้ขึ้นอยู่กับต้นแบบ Javascript บางครั้งคุณสามารถใช้คุณสมบัติขององค์ประกอบเพื่อเข้าถึงแอตทริบิวต์และบางครั้งคุณไม่สามารถทำได้
ก่อนอื่นคุณต้องจำไว้ว่าHTMLElementเป็นวัตถุ Javascript เช่นเดียวกับวัตถุทั้งหมดพวกมันมีคุณสมบัติ แน่นอนว่าคุณสามารถสร้างสถานที่ที่เรียกว่าเกือบทุกอย่างที่คุณต้องการภายในHTMLElementแต่ไม่ต้องทำอะไรกับ DOM (มีอะไรในหน้า) สัญกรณ์จุด ( .) สำหรับคุณสมบัติ ตอนนี้มีคุณสมบัติพิเศษบางอย่างที่ถูกแมปกับแอตทริบิวต์และในเวลาหรือการเขียนมีเพียง 4 ที่รับประกัน (เพิ่มเติมในภายหลัง)
ทั้งหมดHTMLElements attributesรวมถึงคุณสมบัติที่เรียกว่า HTMLElement.attributesเป็นวัตถุถ่ายทอดสด NamedNodeMapที่เกี่ยวข้องกับองค์ประกอบใน DOM "สด" หมายความว่าเมื่อโหนดเปลี่ยนใน DOM พวกเขาเปลี่ยนในด้าน JavaScript และในทางกลับกัน แอตทริบิวต์ DOM ในกรณีนี้คือโหนดที่เป็นปัญหา A Nodeมี.nodeValueคุณสมบัติที่คุณสามารถเปลี่ยนได้ NamedNodeMapวัตถุมีฟังก์ชั่นที่เรียกว่าsetNamedItemที่คุณสามารถเปลี่ยนโหนดทั้งหมด คุณสามารถเข้าถึงโหนดได้โดยตรงโดยใช้กุญแจ ตัวอย่างเช่นคุณสามารถพูดได้ว่า.attributes["dir"]สิ่งใดที่เหมือนกัน.attributes.getNamedItem('dir');(หมายเหตุด้านข้างNamedNodeMapไม่ตรงตามตัวพิมพ์ใหญ่ - เล็กดังนั้นคุณสามารถผ่านได้'DIR')
มีฟังก์ชั่นที่คล้ายกันโดยตรงในHTMLElementที่คุณก็สามารถโทรsetAttributeซึ่งจะสร้างโดยอัตโนมัติโหนดnodeValueถ้ามันไม่ได้อยู่และการตั้งค่า นอกจากนี้ยังมีบางส่วนแอตทริบิวต์คุณสามารถเข้าถึงโดยตรงเป็นคุณสมบัติในการHTMLElementผ่านคุณสมบัติพิเศษdirเช่น นี่คือการทำแผนที่คร่าวๆของสิ่งที่ดูเหมือนว่า:
HTMLElement {
attributes: {
setNamedItem: function(attr, newAttr) {
this[attr] = newAttr;
},
getNamedItem: function(attr) {
return this[attr];
},
myAttribute1: {
nodeName: 'myAttribute1',
nodeValue: 'myNodeValue1'
},
myAttribute2: {
nodeName: 'myAttribute2',
nodeValue: 'myNodeValue2'
},
}
setAttribute: function(attr, value) {
let item = this.attributes.getNamedItem(attr);
if (!item) {
item = document.createAttribute(attr);
this.attributes.setNamedItem(attr, item);
}
item.nodeValue = value;
},
getAttribute: function(attr) {
return this.attributes[attr] && this.attributes[attr].nodeValue;
},
dir: // Special map to attributes.dir.nodeValue || ''
id: // Special map to attributes.id.nodeValue || ''
className: // Special map to attributes.class.nodeValue || ''
lang: // Special map to attributes.lang.nodeValue || ''
}
ดังนั้นคุณสามารถเปลี่ยนdirคุณสมบัติได้ 6 วิธี:
// 1. Replace the node with setNamedItem
const newAttribute = document.createAttribute('dir');
newAttribute.nodeValue = 'rtl';
element.attributes.setNamedItem(newAttribute);
// 2. Replace the node by property name;
const newAttribute2 = document.createAttribute('dir');
newAttribute2.nodeValue = 'rtl';
element.attributes['dir'] = newAttribute2;
// OR
element.attributes.dir = newAttribute2;
// 3. Access node with getNamedItem and update nodeValue
// Attribute must already exist!!!
element.attributes.getNamedItem('dir').nodeValue = 'rtl';
// 4. Access node by property update nodeValue
// Attribute must already exist!!!
element.attributes['dir'].nodeValue = 'rtl';
// OR
element.attributes.dir.nodeValue = 'rtl';
// 5. use setAttribute()
element.setAttribute('dir', 'rtl');
// 6. use the UNIQUELY SPECIAL dir property
element["dir"] = 'rtl';
element.dir = 'rtl';
คุณสามารถปรับปรุงคุณสมบัติทั้งหมดที่มีวิธีการ # 1-5 แต่เพียงdir, id, langและclassNameด้วยวิธีการ # 6
HTMLElementมีคุณสมบัติพิเศษทั้งสี่ องค์ประกอบบางอย่างเป็นคลาสที่ขยายของHTMLElementมีคุณสมบัติที่แมปมากขึ้น ตัวอย่างเช่นHTMLAnchorElementมีHTMLAnchorElement.href, และHTMLAnchorElement.rel HTMLAnchorElement.targetแต่ระวังถ้าคุณตั้งค่าคุณสมบัติเหล่านั้นในองค์ประกอบที่ไม่มีคุณสมบัติพิเศษเหล่านั้น (เช่นบนHTMLTableElement) แล้วแอตทริบิวต์จะไม่เปลี่ยนแปลงและพวกเขาเป็นเพียงคุณสมบัติที่กำหนดเองปกติ เพื่อความเข้าใจที่ดีขึ้นนี่เป็นตัวอย่างของการสืบทอด:
HTMLAnchorElement extends HTMLElement {
// inherits all of HTMLElement
href: // Special map to attributes.href.nodeValue || ''
target: // Special map to attributes.target.nodeValue || ''
rel: // Special map to attributes.ref.nodeValue || ''
}
ตอนนี้คำเตือนครั้งใหญ่: เช่นเดียวกับวัตถุ Javascript ทั้งหมดคุณสามารถเพิ่มคุณสมบัติที่กำหนดเองได้ แต่สิ่งเหล่านี้จะไม่เปลี่ยนแปลงอะไรเลยใน DOM คุณทำได้:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
แต่นั่นก็เหมือนกับ
newElement.myCustomDisplayAttribute = 'block';
ซึ่งหมายความว่าการเพิ่มคุณสมบัติที่กำหนดเองจะไม่ได้รับการเชื่อมโยงกับ.attributes[attr].nodeValue
ประสิทธิภาพ
ฉันได้สร้างกรณีทดสอบ jsperf เพื่อแสดงให้เห็นความแตกต่าง: https://jsperf.com/set-attribute-comparison โดยทั่วไปในการสั่งซื้อ:
dir, id, className)element.attributes.ATTRIBUTENAME.nodeValue = element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValueelement.attributes.ATTRIBUTENAME = newNode element.attributes.setNamedItem(ATTRIBUTENAME) = newNodeสรุป (TL; DR)
ใช้แมปคุณสมบัติพิเศษHTMLElement: element.dir, element.id, หรือelement.classNameelement.lang
หากคุณมั่นใจ 100% องค์ประกอบนั้นเป็นส่วนขยายที่HTMLElementมีคุณสมบัติพิเศษให้ใช้การจับคู่พิเศษนั้น (คุณสามารถตรวจสอบได้if (element instanceof HTMLAnchorElement))
หากคุณเป็น 100% element.attributes.ATTRIBUTENAME.nodeValue = newValueว่าแอตทริบิวต์ที่มีอยู่แล้วการใช้งาน
setAttribute()ถ้าไม่ได้ใช้
classListรับประกันได้ 100% ว่ามีอยู่จริง แต่ไม่ใช่คุณสมบัติสตริง แต่เป็นDOMTokenListวัตถุจริง การตั้งค่า.classNameโดยตรงนั้นเร็วกว่าการปรับเปลี่ยนclassListแต่คุณจะเขียนทับสิ่งทั้งหมด
.valueคุณกำลังเปลี่ยนค่าภายในของHTMLInputElementซึ่งจะสะท้อนให้เห็นถึงคุณลักษณะ stringพวกเขายังไม่จำเป็นต้องเป็น .valueAsNumberจะเปลี่ยนvalue ภายในและstringแบบฟอร์มนั้นจะปรากฏในvalueแอตทริบิวต์ developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"เมื่อใดที่จะใช้ setAttribute vs .attribute = ใน JavaScript?"
กฎทั่วไปคือการใช้.attributeและตรวจสอบว่ามันทำงานบนเบราว์เซอร์
.. ถ้ามันทำงานได้บนเบราว์เซอร์คุณก็สบายดี
..If มันไม่ได้ใช้.setAttribute(attribute, value)แทน.attributeสำหรับที่แอตทริบิวต์
ล้างซ้ำสำหรับคุณลักษณะทั้งหมด
.setAttributeดีถ้าคุณขี้เกียจคุณก็สามารถใช้ ควรทำงานได้ดีบนเบราว์เซอร์ส่วนใหญ่ (แม้ว่าเบราว์เซอร์ที่รองรับ.attributeสามารถปรับแต่งได้ดีกว่า.setAttribute(attribute, value))
ดูเหมือนว่ากรณีหนึ่งที่ควรใช้ setAttribute:
Dev.Opera - จาวาสคริปต์ที่มีประสิทธิภาพ
var posElem = document.getElementById('animation');
var newStyle = 'background: ' + newBack + ';' +
'color: ' + newColor + ';' +
'border: ' + newBorder + ';';
if(typeof(posElem.style.cssText) != 'undefined') {
posElem.style.cssText = newStyle;
} else {
posElem.setAttribute('style', newStyle);
}
posElem.style = newStyleได้กับเบราว์เซอร์ทั้งหมด (ใช้งานได้กับฉันใน Firefox)? มันเป็นเพียงเหตุผลด้านประสิทธิภาพที่setAttributeเป็นที่ต้องการหลีกเลี่ยงการทาสี? คือposElem.style.cssText = newStyleperfomrant มากขึ้นแล้วposElem.style = newStyle?
วิธีการสำหรับการตั้งค่าคุณลักษณะ (ตัวอย่างเช่นคลาส) บนองค์ประกอบ: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (วัตถุ) 4. el.setAttributeNode (โหนด)
ฉันทำแบบทดสอบเกณฑ์มาตรฐาน ( ที่นี่ )
และดูเหมือนว่า setAttributeNode จะเร็วกว่าประมาณ 3 เท่าจากนั้นใช้ setAttribute
ดังนั้นหากประสิทธิภาพเป็นปัญหาให้ใช้ "setAttributeNode"
ซื้อกลับบ้านที่น่าสนใจจากสคริปต์ Google APIเกี่ยวกับเรื่องนี้:
พวกเขาทำเช่นนี้:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
แจ้งให้ทราบว่าพวกเขาใช้setAttributeสำหรับ "src" และ "nonce" แต่แล้ว.async = ...สำหรับแอตทริบิวต์ "async"
ฉันไม่แน่ใจ 100% แต่อาจเป็นเพราะ "async" รองรับเฉพาะเบราว์เซอร์ที่รองรับการ.attr =กำหนดโดยตรง ดังนั้นจึงไม่มีเหตุผลที่จะลองsestAttribute("async")เพราะหากเบราว์เซอร์ไม่เข้าใจ.async=...- จะไม่เข้าใจแอตทริบิวต์ "async"
หวังว่านี่เป็นข้อมูลเชิงลึกที่เป็นประโยชน์จากโครงการวิจัย"Un-Minify GAPI" ที่กำลังดำเนินอยู่ ช่วยแก้ให้ด้วยนะถ้าฉันผิด.
.setAttribute()เป็น[key] = valueทุกอย่างก็เริ่มทำงานได้อย่างน่าอัศจรรย์