Khi nào nên sử dụng setAttribution vs .attribution = trong JavaScript?


234

Có cách thực hành tốt nhất xung quanh việc sử dụng setAttributethay vì .ký hiệu thuộc tính dot ( ) đã được phát triển không?

Ví dụ:

myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");

hoặc là

myObj.className = "nameOfClass";
myObj.id = "someID";

1
Khi tôi chuyển từ .setAttribute()sang [key] = value, mọi thứ bắt đầu hoạt động kỳ diệu.
Andrew

Câu trả lời:


73

Bạn phải luôn luôn sử dụng .attributebiểu mẫu trực tiếp (nhưng xem liên kết quirksmode bên dưới) nếu bạn muốn truy cập theo chương trình trong JavaScript. Nó sẽ xử lý các loại thuộc tính khác nhau (nghĩ "onload") một cách chính xác.

Sử dụng getAttribute/ setAttributekhi bạn muốn xử lý DOM như hiện tại (ví dụ: chỉ văn bản bằng chữ). Các trình duyệt khác nhau gây nhầm lẫn cho hai. Xem chế độ Quirks: tương thích thuộc tính (trong) .


127
Câu trả lời này chưa đủ rõ ràng ... Tôi thực sự không cảm thấy mình hiểu điều này.
tạm_user_name

1
@Aerovistae - đồng ý với bạn về điều này. Đã thêm một câu trả lời mới mà hy vọng rõ ràng hơn.
olan

1
Nhưng nếu bạn muốn ảnh hưởng đến phần bên trong của phần tử, bạn phải sử dụng setAttribution ...
Michael

3
Bạn có nghĩa là outterHTML * :)
megawac

4
Tôi thấy rằng a.href trả về url đầy đủ, nhưng getAttribution ('href') trả về chính xác những gì trong thuộc tính đó (<a href = "/ help" ...).
Thỏ nhựa

144

Từ Javascript: Hướng dẫn dứt khoát , nó làm rõ mọi thứ. Nó lưu ý rằng các đối tượng HTMLE bổ sung của tài liệu HTML xác định các thuộc tính JS tương ứng với tất cả các thuộc tính HTML tiêu chuẩn.

Vì vậy, bạn chỉ cần sử dụng setAttributecho các thuộc tính không chuẩn.

Thí dụ:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works

2
và hơn nữa, nó xuất hiện sau setAttribution cuối cùng trong ví dụ của bạn, node.frameborderKHÔNG được xác định, vì vậy bạn phải getAttribution để lấy lại giá trị.
Michael

5
@Michael đúng - nếu bạn sử dụng setAttribution để đặt giá trị, bạn phải sử dụng getAttribution để truy xuất nó.
olan

3
Không có gì sai khi thiết lập frameBordertrực tiếp, nhưng lưu ý viết hoa. Ai đó nghĩ rằng đó là một ý tưởng hay để camelCase tương đương JavaScript của các thuộc tính HTML. Tôi đã không quản lý để tìm thấy bất kỳ đặc điểm kỹ thuật nào cho việc này, nhưng mạng dường như đồng ý rằng đó là vấn đề của 12 trường hợp cụ thể (ít nhất là đối với HTML 4). Xem ví dụ bài sau: drupal.org/node/1420706#comment-6423420
aaaaaaaaaaaa

1
Các usemapthuộc tính không thể được thiết lập bằng cách sử dụng ký hiệu dấu chấm khi tạo bản đồ tự động cho một hình ảnh. Nó đòi hỏi img.setAttribute('usemap', "#MapName");Câu trả lời của bạn có ngụ ý rằng usemap"không chuẩn" không?
mseifert

1
Điều này chủ yếu là sai. Một số thuộc tính có thuộc tính được xác định, vì vậy không. Nó thực sự chỉ là về cách họ viết thông số kỹ thuật. Nó không có gì để do các thuộc tính là tiêu chuẩn hay không. Tuy nhiên, sự thật là các thuộc tính không có tiêu chuẩn chỉ có thể được truy cập bằng getAttribution ().
Ben

79

Không có câu trả lời nào trước đây là đầy đủ và hầu hết đều chứa thông tin sai lệch.

Có ba cách truy cập các thuộc tính của Phần tử DOM trong JavaScript. Cả ba đều hoạt động đáng tin cậy trong các trình duyệt hiện đại miễn là bạn hiểu cách sử dụng chúng.

1. element.attributes

Các yếu tố có một tài sản thuộc tính rằng lợi nhuận một live NamedNodeMap của attr đối tượng. Các chỉ mục của bộ sưu tập này có thể khác nhau giữa các trình duyệt. Vì vậy, thứ tự không được đảm bảo. NamedNodeMapcó các phương thức để thêm và xóa các thuộc tính ( getNamedItemsetNamedItem, tương ứng).

Lưu ý rằng mặc dù XML phân biệt chữ hoa chữ thường rõ ràng, nhưng thông số DOM gọi các tên chuỗi được chuẩn hóa , do đó các tên được truyền vào getNamedItemkhông phân biệt chữ hoa chữ thường.

Cách sử dụng ví dụ:

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>

2. element.getAttribute&element.setAttribute

Các phương thức này tồn tại trực tiếp trên Elementmà không cần truy cập attributesvà các phương thức của nó nhưng thực hiện các chức năng tương tự.

Một lần nữa, lưu ý rằng tên chuỗi không phân biệt chữ hoa chữ thường.

Cách sử dụng ví dụ:

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>

3. Các thuộc tính trên đối tượng DOM, chẳng hạn như element.id

Nhiều thuộc tính có thể được truy cập bằng các thuộc tính thuận tiện trên đối tượng DOM. Những thuộc tính nào tồn tại phụ thuộc vào loại nút của DOM, chứ không phải thuộc tính nào được xác định trong HTML. Các thuộc tính được định nghĩa ở đâu đó trong chuỗi nguyên mẫu của đối tượng DOM được đề cập. Các thuộc tính cụ thể được xác định sẽ phụ thuộc vào loại Phần tử bạn đang truy cập. Ví dụ, classNameidđược định nghĩa trên Elementvà tồn tại trên tất cả các nút DOM là các phần tử (nghĩa là không phải nút văn bản hoặc nút nhận xét). Nhưng valuehẹp hơn. Nó được định nghĩa trên HTMLInputElementvà có thể không tồn tại trên các yếu tố khác.

Lưu ý rằng các thuộc tính JavaScript là trường hợp nhạy cảm. Mặc dù hầu hết các thuộc tính sẽ sử dụng chữ thường, một số là camelCase. Vì vậy, luôn luôn kiểm tra thông số kỹ thuật để chắc chắn.

"Biểu đồ" này nắm bắt một phần của chuỗi nguyên mẫu cho các đối tượng DOM này. Nó thậm chí không gần hoàn thành, nhưng nó nắm bắt cấu trúc tổng thể.

                      ____________Node___________
                      |               |         |
                   Element           Text   Comment
                   |     |
           HTMLElement   SVGElement
           |         |
HTMLInputElement   HTMLSpanElement

Cách sử dụng ví dụ:

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>

Hãy cẩn thận: Đây là một lời giải thích về cách xác định HTML và các trình duyệt hiện đại xử lý các thuộc tính. Tôi đã không cố gắng để đối phó với những hạn chế của các trình duyệt bị hỏng, cổ xưa. Nếu bạn cần hỗ trợ các trình duyệt cũ, ngoài thông tin này, bạn sẽ cần biết những gì bị hỏng trong các trình duyệt đó.


Cảm ơn cho thanh toán bù trừ này lên. Tôi tò mò, phiên bản IE nào được coi là 'hiện đại' và tuân theo thông số HTML?
jkdev

3
@jkdev IE không bao giờ trở nên hiện đại. Những gì nó đã trở nên cũ.
Suraj Jain

Cảm ơn câu trả lời chi tiết như vậy, tôi đã đọc rất nhiều về DOM và tính kế thừa như HTMLEuity kế thừa từ Element và v.v., câu trả lời của bạn rất hợp lý.
Suraj Jain

16

Một trường hợp tôi tìm thấy khi setAttributecần thiết là khi thay đổi thuộc tính ARIA, vì không có thuộc tính tương ứng. Ví dụ

x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');

Không có x.arialabelhoặc bất cứ điều gì tương tự, vì vậy bạn phải sử dụng setAttribution.

Chỉnh sửa: x ["aria-nhãn"] không hoạt động . Bạn thực sự cần setAttribution.

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"

thực sự không thực sự trong Javascript, bạn có thể làm điều này x ["aria-nhãn"]
Fareed Alnamrouti

@fareednamrouti Điều đó không hiệu quả. Tôi chỉ thử nó. Các thuộc tính JS không ảnh hưởng đến các thuộc tính html. Bạn thực sự cần setAttribution ở đây.
Antimon

@Antimony Điều này thật lạ nhưng Có bạn đúng 100% tôi sẽ bỏ phiếu
Fnamed Alnamrouti 24/07/2015

2
Bạn có chắc chắn không có ariaLabel?
jgmjgm

8

Những câu trả lời này không thực sự giải quyết được sự nhầm lẫn lớn giữa các thuộc tínhthuộc tính . Ngoài ra, tùy thuộc vào nguyên mẫu Javascript, đôi khi bạn có thể sử dụng thuộc tính của một thành phần để truy cập một thuộc tính và đôi khi bạn không thể.

Đầu tiên, bạn phải nhớ rằng an HTMLElementlà một đối tượng Javascript. Giống như tất cả các đối tượng, chúng có thuộc tính. Chắc chắn, bạn có thể tạo một thuộc tính được gọi là gần như mọi thứ bạn muốn bên trong HTMLElement, nhưng nó không phải làm bất cứ điều gì với DOM (những gì trên trang). Ký hiệu dấu chấm ( .) là dành cho các thuộc tính . Bây giờ, có một số thuộc tính đặc biệt được ánh xạ tới các thuộc tính, và tại thời điểm hoặc viết chỉ có 4 thuộc tính được đảm bảo (nhiều hơn về sau).

Tất cả HTMLElementbao gồm một tài sản được gọi là attributes. HTMLElement.attributeslà một đối tượng trực tiếp NamedNodeMap liên quan đến các yếu tố trong DOM. "Live" có nghĩa là khi nút thay đổi trong DOM, chúng sẽ thay đổi ở phía JavaScript và ngược lại. Thuộc tính DOM, trong trường hợp này, là các nút trong câu hỏi. A Nodecó một .nodeValuetài sản mà bạn có thể thay đổi. NamedNodeMapcác đối tượng có một hàm được gọi là setNamedItemnơi bạn có thể thay đổi toàn bộ nút. Bạn cũng có thể truy cập trực tiếp vào nút bằng phím. Ví dụ, bạn có thể nói .attributes["dir"]cái nào giống như .attributes.getNamedItem('dir');(Ghi chú bên, NamedNodeMapkhông phân biệt chữ hoa chữ thường, vì vậy bạn cũng có thể vượt qua 'DIR');

Có một chức năng tương tự trực tiếp trong HTMLElementđó bạn chỉ có thể gọi setAttributenó sẽ tự động tạo một nút nếu nó không tồn tại và đặt nodeValue. Ngoài ra còn có một số thuộc tính bạn có thể truy cập trực tiếp dưới dạng các thuộc tính HTMLElementthông qua các thuộc tính đặc biệt , chẳng hạn như dir. Đây là một bản đồ sơ bộ của nó trông như thế nào:

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 || ''

}

Vì vậy, bạn có thể thay đổi các dirthuộc tính 6 cách:

  // 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';

Bạn có thể cập nhật tất cả các thuộc tính với phương pháp # 1-5, nhưng chỉ dir, id, lang, và classNamevới phương pháp # 6.

Phần mở rộng của HTMLEuity

HTMLElementcó 4 tính chất đặc biệt Một số phần tử là các lớp mở rộng HTMLElementcó các thuộc tính được ánh xạ nhiều hơn. Ví dụ, HTMLAnchorElementHTMLAnchorElement.href, HTMLAnchorElement.relHTMLAnchorElement.target. Nhưng, hãy cẩn thận , nếu bạn đặt các thuộc tính đó trên các thành phần không có các thuộc tính đặc biệt đó (như trên a HTMLTableElement) thì các thuộc tính không thay đổi và chúng chỉ là các thuộc tính tùy chỉnh thông thường. Để hiểu rõ hơn, đây là một ví dụ về sự kế thừa của nó:

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

Thuộc tính tùy chỉnh

Bây giờ cảnh báo lớn: Giống như tất cả các đối tượng Javascript , bạn có thể thêm các thuộc tính tùy chỉnh. Nhưng, những thứ đó sẽ không thay đổi bất cứ điều gì trên DOM. Bạn có thể làm:

  const newElement = document.createElement('div');
  // THIS WILL NOT CHANGE THE ATTRIBUTE
  newElement.display = 'block';

Nhưng đó là giống như

  newElement.myCustomDisplayAttribute = 'block';

Điều này có nghĩa là việc thêm một thuộc tính tùy chỉnh sẽ không được liên kết đến.attributes[attr].nodeValue .

Hiệu suất

Tôi đã xây dựng trường hợp thử nghiệm jsperf để hiển thị sự khác biệt: https://jsperf.com/set-attribution-comparison . Về cơ bản, theo thứ tự:

  1. Thuộc tính tùy chỉnh vì chúng không ảnh hưởng đến DOM và không phải là thuộc tính .
  2. Ánh xạ đặc biệt được cung cấp bởi trình duyệt ( dir, id, className).
  3. Nếu thuộc tính đã tồn tại ,element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribution ();
  5. Nếu thuộc tính đã tồn tại ,element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

Kết luận (TL; DR)

  • Sử dụng ánh xạ bất động sản đặc biệt từ HTMLElement: element.dir, element.id, element.className, hoặc element.lang.

  • Nếu bạn chắc chắn 100% phần tử là phần mở rộng HTMLElementcó thuộc tính đặc biệt, hãy sử dụng ánh xạ đặc biệt đó. (Bạn có thể kiểm tra với if (element instanceof HTMLAnchorElement)).

  • Nếu bạn chắc chắn 100% thuộc tính đã tồn tại, hãy sử dụng element.attributes.ATTRIBUTENAME.nodeValue = newValue.

  • Nếu không, sử dụng setAttribute().


Bạn đã đề cập đến bốn ánh xạ thuộc tính này: dir, id, className và lang. Còn classList thì sao? Là ClassList một ánh xạ thuộc tính được đảm bảo tồn tại?
Barzee

classListđược đảm bảo 100% để tồn tại, nhưng nó không phải là một thuộc tính chuỗi, nó là một DOMTokenListđối tượng sống . Cài đặt .classNametrực tiếp nhanh hơn thao tác classList, nhưng bạn sẽ ghi đè lên toàn bộ.
ShortFuse

Làm thế nào về .value trên thẻ <input> và <textarea>? Họ là loại gì?
Daniel Williams

Những cái được đề cập trong câu trả lời là cái mà W3C gọi là "phản ánh các thuộc tính IDL". Khi bạn thay đổi .value, bạn đang thay đổi giá trị bên trong của HTMLInputElement, sau đó được phản ánh trên các thuộc tính. Họ cũng không cần phải như vậy string. .valueAsNumbersẽ thay đổi value bên trongstringhình thức của nó sẽ xuất hiện trong valuethuộc tính. developer.mozilla.org/en-US/docs/Web/HTML/Attribution
ShortFuse

3

"Khi nào nên sử dụng setAttribution so với .attribution = trong JavaScript?"

Một quy tắc chung là sử dụng .attributevà kiểm tra nếu nó hoạt động trên trình duyệt.

..Nếu nó hoạt động trên trình duyệt, bạn nên đi.

..Nếu không, sử dụng .setAttribute(attribute, value)thay vì .attributecho thuộc tính đó .

Rửa sạch lặp lại cho tất cả các thuộc tính.

Vâng, nếu bạn lười biếng, bạn chỉ cần sử dụng .setAttribute. Điều đó sẽ hoạt động tốt trên hầu hết các trình duyệt. (Mặc dù các trình duyệt hỗ trợ .attributecó thể tối ưu hóa nó tốt hơn .setAttribute(attribute, value).)


0

Điều này trông giống như một trường hợp tốt hơn là sử dụng setAttribution:

Dev.Opera - JavaScript hiệu quả

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

2
Cảm ơn đã chia sẻ tomo7 này, bạn có thể vui lòng giải thích thêm một chút. Không posElem.style = newStylehoạt động trong tất cả các trình duyệt (làm việc cho tôi trong Firefox)? Có phải chỉ vì lý do hiệu suất setAttributeđược ưa thích, tránh việc sơn lại? Là posElem.style.cssText = newStylenhiều nước hoa hơn sau đó posElem.style = newStyle?
Noitidart

0

các phương thức để thiết lập các thuộc tính (ví dụ lớp) trên một phần tử: 1. el.groupName = chuỗi 2. el.setAttribution ('class', chuỗi) 3. el.attribut.setNamedItem (object) 4. el.setAttributionNode (nút)

Tôi đã thực hiện một bài kiểm tra điểm chuẩn đơn giản ( ở đây )

và có vẻ như setAttributionNode nhanh hơn khoảng 3 lần sau đó sử dụng setAttribution.

vì vậy nếu hiệu suất là một vấn đề - hãy sử dụng "setAttributionNode"


Tôi nghĩ rằng bạn chạy thử nghiệm trên chrome. Tôi đã xử lý trên máy Mac của mình bằng chrome, safari và firefox; dự kiến ​​3 trong số họ cho thấy 3 kết quả khác nhau.
Olgun Kaya

0

Điều thú vị từ tập lệnh Google API liên quan đến điều này:

Họ làm như thế này:

var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";

Lưu ý, cách họ sử dụng setAttributecho "src" và "nonce", nhưng sau đó .async = ...cho thuộc tính "async".

Tôi không chắc chắn 100%, nhưng có lẽ đó là vì "async" chỉ được hỗ trợ trên các trình duyệt hỗ trợ .attr =gán trực tiếp . Vì vậy, sẽ không có ý nghĩa gì khi cố gắng sestAttribute("async")vì nếu trình duyệt không hiểu .async=...- nó sẽ không hiểu thuộc tính "async".

Hy vọng rằng, đó là một cái nhìn sâu sắc hữu ích từ dự án nghiên cứu "Un-minify GAPI" đang diễn ra của tôi . Sửa tôi nếu tôi sai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.