5.6 操作元素特性
几乎跟获取元素内容一样,获取和设置元素特性(attribute)的值也是最频繁的操作之一。通常,元素自带的特性列表会随着元素自身的XML表示信息预先加载,并存储成关联数组备用,例如以下这个网页的HTML片段:
<form name="myForm" action="/test.cgi" method="POST">
...
</form>
一旦加载到DOM中,表示HTML表单元素的变量formElem就会有一个关联数组,它是名/值特性对。其结果大致如下:
formElem.attributes = {
name: "myForm",
action: "/test.cgi",
method: "POST"
};
检查元素特性是否存在对于使用特性数组来说是最简单不过的,但还是存在一个问题:不知何故Safari不支持。最为严重的是,IE也不支持可能是最有用的hasAttribute函数。那么如何才能检查某个特性是否存在呢?一个可行的办法是使用getAttribute函数(我将会在下一节讲述)并且检查返回值是否为null,如代码清单5-17所示。
代码清单5-17 检查元素是否有用一个指定的特性
function hasAttribute( elem, name ) {
return elem.getAttribute(name) != null;
}
有了这个函数,并了解特性如何使用,那么你就可以获取和设置特性的值了。
获取和设置特性的值
根据你所使用的DOM文档的类型,从元素中获取特性的信息有两种方法。如果你希望保险并且总是兼容通用XML DOM的方式,那么可用getAttribute和setAttribute。可以使用如下方法:
// 获取特性
id("everywhere").getAttribute("id")
// 设置特性的值
tag("input")[0].setAttribute("value","Your
Name");
除了这对标准的getAttribute/setAttribute外,HTML DOM文档还有作为快速特性获取器(getter)/设置器(setter)的额外属性集合。它们通常在现代浏览器的DOM实现中都可用(但只能给HTML DOM文档打包票),使用它们十分有助于编写精炼的代码。以下的代码向你展示了如何使用DOM属性(property)同时取得和设置DOM特性:
// 快捷获取特性
tag("input")[0].value
// 快捷设置特性
tag("div")[0].id = "main";
你应该注意到,特性存在某些怪异的情形。最常碰到问题的情形之一是存取类名称特性。为了能在所有的浏览器中都生效,你必须使用elem.className来存取className特性,而不是使用看起来更合适的getAttribute("class")。这种情形也发生在for特性上,而它被另外起名为htmlFor。此外,这也会在一些CSS特性上发生:cssFloat和cssText。导致这些特别的命名约定是因为class、for、float和text等都是JavaScript的保留字。
为了补救这些怪异的情形并且简化获取、设置正确特性的处理流程,你应该使用一个辅助函数来处理这些特殊情形。代码清单5-18展示了一个获取和设置元素特性值的函数。使用两个参数来调用这个函数时,比如attr(element,id),返回指定元素特性的值;而使用3个参数来调用的话,比如attr(element,class,test),则是设置特性的值并返回它的新值。
代码清单5-18 获取和设置元素特性的值
function attr(elem, name, value) {
// 确保提供的 name 是正确的
if ( !name || name.constructor != String ) return '';
// 检查name是否处在怪异命名的情形中
name = { 'for': 'htmlFor', 'class': 'className' }[name] || name;
// 如果用户传入了value参数的话,那么
if ( typeof value != 'undefined' ) {
// 首先使用快捷方式
elem[name] = value;
// 可以的话,使用setAttribute
if ( elem.setAttribute )
elem.setAttribute(name,value);
}
// 返回特性的值
return elem[name] || elem.getAttribute(name) || '';
}
不用关心具体实现,使用标准的方法来同时存取和改变特性是一个强大的工具。代码清单5-19展示了一些例子,从中你可以学习到如何在多种场合中使用attr函数来简化处理特性的流程。
代码清单5-19 在DOM元素中使用attr函数设置和获取特性的值
// 设置<h1>元素的class
attr( tag("h1")[0], "class", "header" );
// 设置各个<input>元素的值
var input = tag("input");
for ( var i = 0; i < input.length; i++ ) {
attr( input[i], "value", "" );
}
// 为name的值是'invalid'的<input>元素增加边框
var input = tag("input");
for ( var i = 0; i < input.length; i++ ) {
if ( attr( input[i], "name" ) == 'invalid' ) {
input[i].style.border = "2px solid red";
}
}
到目前为止,我们已经讨论了DOM中常用的特性(比如id、class、name等)的获取和设置。但是,还有一个派得上用场的技术,那就是设置和获取非传统的特性。比如,你可以增添一个新特性(它只对存取DOM版本的元素可见)然后再次获取,完全不用修改文档的实际属性。举个例子,假设你有一个术语的自定义列表,并需要在点击术语的时候展开它的描述,HTML的结构大致如代码清单5-20所示。
代码清单5-20 自定义列表的HTML,其中把描述事先隐藏起来
<html>
<head>
<title>Expandable Definition List</title>
<style>dd { display: none; }</style>
</head>
<body>
<h1>Expandable Definition List</h1>
<dl>
<dt>Cats</dt>
<dd>A furry, friendly, creature.</dd>
<dt>Dog</dt>
<dd>Like to play and run around.</dd>
<dt>Mice</dt>
<dd>Cats like to eat them.</dd>
</dl>
</body>
</html>
我们将会在第6章详细讲解事件的细节,现在先尽量保持这些事件代码的简单。以下例子是一个能让你点击术语显示(或隐藏)描述的高效脚本。该脚本应在页面的头部或者从一个外部文件中引入。代码清单5-21展示了构建一个可扩展自定义列表的必要代码。
代码清单5-21 允许动态切换的自定义列表
// 直至DOM可用
domReady(function(){
// 遍历所有的术语
var dt = tag("dt");
for ( var i = 0; i < dt.length; i++ ) {
// 等待用户点击术语
addEvent( dt[i], "click", function() {
// 检查描述已经open与否
var open = attr( this, "open" );
// 切换描述的display
next( this ).style.display = open ? 'none' : 'block';
// 记录描述是否open
attr( this, "open", open ? '' : 'yes' );
});
}
});
现在已经知道如何遍历DOM与如何检查及修改特性,接下来你需要学习如何创建新的DOM元素,插入到所需的地方,并删除不再需要的元素。






