Attributes and custom properties(特性与自定义属性)

在微博上看到有人讨论 attributes 与 properties,甚至 arguments 与 parameters 的区别。正好在看到一篇好的网文,翻译共享。

文本来自:Attributes and custom properties ——By llya Kantor

Attributes and custom properties(特性与自定义属性)

  1. Properties
  2. Attributes
  3. Properties 和 Attributes 的同步
    1. id
    2. href
    3. value
    4. class/className
    5. 旧式IE浏览器的乐趣
    6. 作为DOM节点的 Attributes
  4. 总结

一个 DOM 节点包含 attributes 和 properties。因为彼此间相互关联,人们常常将他们混合在一起,但他们确是两种不同的东西。

Properties(属性)

DOM 节点是一个对象,因此可以像 Javascript 中的对象一样存储自定义的 properties 和 methods。

例子展示了如何给 document.body 添加 properties 和 methods:

document.body.myData = { 
  name: 'John'
};
alert(document.body.myData.name); // John

document.body.sayHi = function() { 
  alert(this.nodeName);
};
 
document.body.sayHi();  // BODY

自定义的 properties 和 methods 仅在 Javascript 中可见,并影响 HTML 。

同时,自定义 properties 与本地 properties 可用 for..in 循环展示出来:

document.body.custom = 5;

var list = [];
for(var key in document.body) {
  list.push(key);
}

alert(list.join('\n'));

自定义的 DOM properties:

  • 可为任何类型的值,属性名对大小写敏感。
  • 不影响HTML。

 

Attribute(特性)

DOM 节点提供如下访问 HTML attributes的标准方法:

  elem.hasAttribute(name) - 检查attribute是否存在

  elem.getAttribute(name)  - 获得attribute的值

  elem.setAttribute(name, value) - 设置attribute

  elem.removeAttribute(name) - 删除attribute

 

IE 8的兼容模式及其以下版本破坏了attributes,这些版本:

  • 只提供了 getAttribute 和 setAttribute 方法
  • 实际修改的是 DOM propertied,而不是 attributes
  • IE 8以下版本中合并了 Attribute 与 property。虽然有时会导致奇怪的结果,但是我们在这讨论的对 attributes 操作方法仍然有效。

 

对比 properties,attributes 具有:

  1. 可能只能是字符串(有些会用 toString() 转换)
  2. 名称对大小写不敏感,因为 HTML attributes是不敏感的
  3. 可在 innerHTML 中显示(除非是老的 IE 版本)
  4. 可以用元素属性 .attributes 来列出所有的 attribute,它是个类数组。

如下例子中展示了一个 HTML 结构,并对其设置 attributes:

<body>
  <div about="Elephant" class="smiling"></div>

  <script>
    var div = document.body.children[0]
    alert( div.getAttribute('ABOUT') ) // (1)
    
    div.setAttribute('Test', 123)      // (2)
    alert( document.body.innerHTML )   // (3)
  </script>
</body>

当运行上述代码,注意数字标注的几点:

  1. 虽然 getAttribute('ABOUT‘) 用了大写名称,但并不影响结果。
  2. 可以对 attribute 设置字符串或其他基本类型,这些都将会自动转换成字符串。对象本应当自动转换,但在 IE 中存在问题,因此请坚持使用基本类型。
  3. innerHTML 中包括了新的 ‘test' attribute。

 

Properties 与 Attributes 的同步

每种 DOM 节点都有标准的属性。

例如,‘A’标签:Interface HTMLAnchorElement。它包含有 'href' 、'accessKey' 以及其他特定的属性。除此之外,它还从 HTMLElement 那继承了 'id' 即其他attribute。

标准的 DOM properties 与 attributes 是同步的。

id

例如,浏览器中 'id‘ attribute与 'id' property是同步的。

<script>
  document.body.setAttribute('id','la-la-la');
  alert(document.body.id);  // la-la-la
</script>

href

但同步不能保证值也相同。来看看例子中的 ‘href' 属性:

<a href="#"></a>
<script>
  var a  = document.body.children[0];

  a.href = '/'
  alert( 'attribute:' + a.getAttribute('href') ); // '/'
  alert( 'property:' + a.href );  // IE: '/', others: full URL
</script>

这是因为根据 W3C specification,href 必须是一个 ‘well-formed’(良好形式)的链接。

还有一些属性,它们是同步的,但对于 properties 和 attributes 却不是相同的副本。例如 input.checked :

<input type="checkbox" checked>

<script>
  var input  = document.body.children[0];

  alert( input.checked ); // true
  alert( input.getAttribute('checked') ); // empty string
</script>

input.checked 的 property 只能是 true 或者 false,但 attribute可以是任何输入的值。

value

同样存在一些 'one-way‘(单向)同步的内置属性。

例如,input.value 从 attribute 中同步(即 property 从 attribute 中获得同步):

<body>
  <input type="text" value="markup">
  <script>
    var input = document.body.children[0];

    input.setAttribute('value', 'new');

    alert( input.value ); // 'new', input.value changed
  </script>
</body>

但是 attribute 不能从 property 中获得同步:

<body>
  <input type="text" value="markup">
  <script>
    var input = document.body.children[0];

    input.value = 'new';

    alert(input.getAttribute('value'));  // 'markup', not changed!
  </script>
</body>

例如当访问者输入了某些字符后,'value' attribute 在 property 更新后维持了原始值。原始值可以用来检验 input 是否变化,或者重置它。

class/className

名称的特例:attribute 中的 ‘class’ 对应 property中的 ‘className’

因为 ‘class' 是 Javascript 的保留字,attribute的 ‘class’ 对应的 property 名称是 ‘className’:

<body>
  <script>
    document.body.setAttribute('class', 'big red bloom');

    alert( document.body.className );  // ^^^
  </script>
</body>

注意,上述例子在 IE 9以下的版本不可用,因为怪异模式混合了 properties 和 attributes。

只要始终使用 className property而不是 class attribute,就可以避免浏览器差异带来的麻烦。

 

旧式IE浏览器的乐趣

首先,IE 9以下的版本同步了所有的 property 和 attribute。

document.body.setAttribute('try-in-ie', 123)

alert( document.body['try-in-ie'] === 123 )  // true in IE<9

注意到这里的变量(123)类型是一样的,attribute 并没有将其转换成字符串(实际上它应该转换)。

其次,在 IE 8以下版本(以及IE 8的IE 7兼容模式)的 properties和 attributes 是相同的。因此产生了一些有趣的结果。

例如,properties 的名称是大小写敏感的,attributes 却不是。如果浏览器认为它们是相同的,那下面的结果将会是什么样的呢?

document.body.abba = 1 // assign property (now can read it by getAttribute)
document.body.ABBA = 5 // assign property with another case

// must get a property named 'ABba' in case-insensitive way.
alert( document.body.getAttribute('ABba') ) // ??

浏览器为了避免这种情况,将获得名称的首字母作为默认的大写小形式。IE 还为 getAttribute 提供了一个可选的参数,用来指定大小写形式。详见  MSDN getAttribute

除了IE 9以下版本的浏览器都可用 ‘class’ attribute 来改变 class 的值。但尽量不要使用它,始终用‘className’ property 代替。

要想在IE中生存,必须确保正确地使用 attributes。

或者,始终使用 properties,除非你确实需要用attributes。

确实需要用 attributes 的情况包括:

  1. 获得自定义的HTML attribute,因为它并不同步到DOM的 property 中。
  2. 获得标准HTML attributes 的原始值,例如<INPUT value = '...'>。

作为DOM 节点的 attributes

可以通过 elem.attributes 集合访问元素的 attributes。

在 attributes 集合中,所有 attribute 都可以表示成一个特殊的DOM节点。它包括名称、值和其他属性。

例如:

<span style="color:blue" id="my">text</span>

<script>
  var span = document.body.children[0];
  alert( span.attributes['style'].value );  // "color:blue;"
  alert( span.attributes['id'].value );     // "my"
</script>

另外,在IE 8的兼容模式及其以下版本在处理 ‘style’ 属性时会变得疯狂……猜猜为啥?

Attribute DOM节点不是文档树的一部分,仅仅可从元素来访问它们。

 

总结

Attributes 和 properties 都是DOM模型的核心特征。

他们的异同表:

property   attribute
任意值 字符串
名称对大小写敏感 不敏感
innerHTML中不显示 显示
标准的 DOM properties 和 attributes 是同步的,自定义的不是
IE 8兼容模式及其以下版本将 attributes 与 properties 混合起来,并且弄得很糟糕

 

 

 

 

 

 

如果需要在 HTML中自定义 attributes,可以在HTML5中使用  ‘date-* attribute‘ 的形式。详见HTML5标准中的Custom data attributes部分。

在实际应用中,98%的 DOM 操作都是使用 properties。

只有两种情形需要使用attributes:

  1. 自定义 HTMLattributes,因为它并不同步到DOM property。
  2. 访问内置的 HTML attributes,这些 attribute 不能从 property 同步过来。例如 INPUT标签的value值。
posted @ 2013-04-24 14:27  蓝莓调调  阅读(544)  评论(0编辑  收藏  举报