1、概述web
attribute和property是經常被弄混的兩個概念。url
簡單來講,property則是JS代碼裏訪問的:prototype
document.getElementByTagName('my-element').prop1 = 'hello';server
attribute相似這種:對象
<my-element attr1="cool" />ip
JS代碼裏訪問attribute的方式是getAttribute和setAttribute:element
document.getElementByTagName('my-element').setAttribute('attr1','Hello');字符串
document.getElementByTagName('my-element').getAttribute('attr1','Hello');get
2、區別input
多數狀況下,二者是等效的。在web標準中,經常會規定某attribute「反射」了同名的property。可是例外的狀況仍是很多的。
1. 名字不一致
最典型的是className,爲了迴避JavaScript保留字,JS中跟class attribute對應的property是className。
<div class="cls1 cls2"></div>
<script>
var div = document.getElementByTagName('div');
div.className //cls1 cls2
</scrpit>
2. 類型不一致
最典型的是style,不接受字符串型賦值。
<div class="cls1 cls2" style="color:blue" ></div>
<script>
var div = document.getElementByTagName('div');
div.style // 對象
</scrpit>
3. 語義不一致
如a元素的href屬性。
<a href="//m.taobao.com" ></div>
<script>
var a = document.getElementByTagName('a');
a.href // 「http://m.taobao.com」,這個url是resolve過的結果
a.getAttribute('href') // 「//m.taobao.com」,跟HTML代碼中徹底一致
</scrpit>
4. 單向同步關係
value是一個極爲特殊的attribute/property。
<input value = "cute" />
<script>
var input = document.getElementByTagName('input');
//若property沒有設置,則結果是attribute
input.value //cute
input.getAttribute('value'); //cute
input.value = 'hello';
//若value屬性已經設置,則attribute不變,property變化,元素上實際的效果是property優先
input.value //hello
input.getAttribute('value'); //cute
</scrpit>
除此以外,checkbox的顯示狀態由checked和indeterminate兩個property決定,而只有一個名爲checked的property,這種狀況下property是更完善的訪問模型。
3、特殊場景
1.mutation
使用mutation observer,只能監測到attribute變化。
var observer = new MutationObserver(function(mutations){
for(var i = 0; i < mutations.length; i++) {
var mutation = mutations[i];
console.log(mutation.attributeName);
}
});
observer.observe(element,{attributes:true});
element.prop1 = 'aa' // 不會觸發
element.setAttribute('attr1', 'aa') //會觸發
2.custom element
在使用WebComponents時,能夠定義attribute和property,二者能夠互相反射,也能夠全無關聯。
var MyElementProto = Object.create(HTMLElement.prototype, {
createdCallback : {
value : function() { }
}
});
//定義property
Object.defineProperty(MyElementProto,'prop1', {
get:function(){
return //
},
set:function(){
console.log('property change');//do something
}
});
//定義attribute
MyElementProto.attributeChangedCallback = function(attr, oldVal, newVal) {
if(attr === 'attr1') {
console.log('attribute change');//do something
}
};
window.MyElement = document.registerElement('my-element', {
prototype: MyElementProto
});