一、三位一体的网页
- 结构层:由HTML或XHTML之类的标记语言负责创建
- 表示层:由CSS负责完成
- 行为层:负责内容如何响应事件,由javascript和DOM负责。
二、style属性
例如,有以下例子
<p id="example" style="color:grey;font-family:'Arial',sans-serif;">An example of paragraph
</p>
style属性包含着元素的样式,查询这个属性将返回一个对象。
1.获取样式
为查出某个元素在浏览器中的颜色,需要使用style对象中的color属性:
element.style.color
绝大部分样式表的属性的返回值与它们的设置值都采用同样的单位,但存在例外。如color属性值是#999999,在有些浏览器里,其在DOM中的color属性是以RGB格式的颜色值返回。
注意:需要饮用一个中间带有减号的CSS属性,DOM要求使用驼峰是命令,如font-family可以转换为fontFamily
通过style属性获取样式有很大的局限性,style属性只能返回内嵌样式,即只有把CSS style属性插入到标记里,才可以使用DOM style属性去查询这些信息。
2.设置样式
style对象的各个属性都是可读写的,可以用赋值语句来更新样式
element.style.property = value
style对象的属性值永远是一个字符串,因此其数值值必须放在引号里,否则javascript会解释成一个变量,引发错误。
三、何时该用DOM脚本设置样式
在绝大多数场合,还是应该是会用CSS去声明样式,在一些使用CSS不方便的场合,可以利用DOM对文档的样式做一些增强。
1.根据元素在节点树中的位置来设置样式
通过CSS声明样式的方式主要有3种:
- 为标签元素统一地声明样式
p {
font-size:1em;
}
- 为特定class属性的所有元素统一声明样式
.fineprint {
font-size:.8em;
}
- 为独一无二的id属性单独声明样式
#intro {
font-size:1.2em;
}
现今,CSS还无法根据元素之间的相对位置关系找出某个特定的元素,但这对DOM来说很容易实现。我们可以利用DOM找出文档中所有的h1元素,然后找出紧跟在每个h1元素后面的元素,并为它们添加样式。
如:
首先用getElementsByTagName方法把所有的h1标签找出来,然后遍历这个节点里的所有元素,文档里的下一个节点可以用silbing属性查找出来。注意:这里需要的是下一个元素节点,因此需要编写getNextElement函数。
function styleHeaderSibling(){
if (!document.getElementsByTagName) return false;
var headers = document.getElementsByTagName("h1");
var elem;
for(var i=0;i<headers.length;i++){
headers[i].nextSibling
elem = getNextElement(headers[i].nextSibling);
elem.style.fontWeight = "bold";
elem.style.fontSize = "1.2em";
}
}
function getNextElement(node){
if (node.nodeType == 1) return node;
if (node.nextSibling) return getNextElement(node.nextSibling);
return false;
}
addLoadEvent(styleHeaderSibling);
对应的htm文档:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Man bites dog</title>
</head>
<body>
<h1>Hold the front page</h1>
<p>This first paragraph leads you in.</p>
<p>The most important information is delivered first.</p>
<h1>Extra! Rxtra!</h1>
<p>Further developments are unfolding.</p>
<p>You can read all about it here.</p>
<script src="scripts/addLoadEvent.js"></script>
<script src="scripts/styleHeaderSibling.js"></script>
</body>
</html>
2.根据某种条件反复设置某种样式
表格:
让表格里的行更可读的常用技巧是交替改变它们的背景色,从而使相邻的两行泾渭分明。如果浏览器支持CSS 3,只需要如下两行样式:
tr:nth-child(odd){
background-color:#ffc;
}
tr:nth-child(even){
background-color:#fff;
}
如果:nth-child()不可用,只好采用另外的技术。有一种方案是为每个奇数行设置一个class即可,但是不够方便,特别是以后要在这个表格的中间插入或删除行,需要手动更新大量的class属性。
可以利用javascript使用for或while循环来遍历。
function stripeTables(){
if (!document.getElementsByTagName) return false;
var tables = document.getElementsByTagName("table");
var odd,rows;
for (var i=0;i<tables.length;i++){
odd = false;
rows = tables[i].getElementsByTagName("tr");
for (var j=0;j<rows.length;j++){
if (odd == true){
rows[j].style.backgroundColor = "#ffc";
odd = false;
}else{
odd = true;
}
}
}
}
addLoadEvent(stripeTables);
对应的html代码:
<DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Cities</title>
<link rel="stylesheet" media="screen" href="styles/format.css">
</head>
<body>
<table>
<caption>Itinerary</caption>
<thead>
<tr>
<th>When</th>
<th>Where</th>
</tr>
</thead>
<tbody>
<tr>
<td>June 9th</td>
<td>Portland,<abbr title="Oregon">OR</abbr></td>
</tr>
<tr>
<td>June 10th</td>
<td>Seattle,<abbr title="Washington">WA</abbr></td>
</tr>
<tr>
<td>June 12th</td>
<td>Sacramento,<abbr title="Califonia">CA</abbr></td>
</tr>
</tbody>
</table>
<script src="scripts/addLoadEvent.js"></script>
<script src="scripts/stripeTables.js"></script>
</body>
</html>
3.响应事件
CSS提供的:hover等伪class属性允许我们根据HTML元素的状态来改变样式。DOM也可以通过onmouseover等事件对HTML元素的状态变化作出相应。
很难判断何时应该使用:hover属性,何时应该使用onmouseover事件。最简单的方法就是选择最容易实现的办法。
比如,如果想让链接在鼠标指针悬停在其上时改变颜色,就选用CSS
a:hover{
color:#c60;
}
伪类:hover已经得到了绝大多数浏览器的支持——至少被用来改变链接样式时是如此。但如果想利用该伪类在鼠标悬停在其他元素上时改变样式,支持这种用法的浏览器就没那么多了。
如果想让某行在鼠标指针悬停其上时改变文本变为粗体,可以使用CSS(以前面的html为例)
tr:hover{
font-weight:bold;
}
然而,在实际中,只有部分浏览器看到效果。
在这种场合,使用DOM改变HTML元素的样式更切合实际。
编写函数highlightRows函数,将鼠标指针选悬停在某个表格行的上方时,把该行文本加黑加粗。
function highlightRows(){
if (!document.getElementsByTagName) return false;
var rows = document.getElementsByTagName("tr");
for (var i=0;i<rows.length;i++){
rows[i].onmouseover = function(){
this.style.fontWeight = "bold";
}
rows[i].onmouseout = function(){
this.style.fontWeight = "normal";
}
}
}
addLoadEvent(highlightRows);
4.className属性
className是一个可读/可写的属性,凡是元素节点都有这个属性。
for(var i=0;i<headers.length;i++){
headers[i].nextSibling
elem = getNextElement(headers[i].nextSibling);
elem.style.fontWeight = "bold";
elem.style.fontSize = "1.2em";
}
观察以上代码,如果想要将紧跟在一级标题后的元素的CSS改为1.4em,需要去改变这个函数。如果引用一个外部CSS样式表,并且其中有一条针对.intro类的样式声明:
.intro{
font-weight:bold;
font-size:1.2em;
}
现在只需要在styleHeaderSibling函数里将紧跟在一级标题后的元素的class属性设置为intro即可达到同样的目的。可以使用setAttribute方法,element.setAttribute(“class”,“intro”),也使用直接更新className属性。
function styleHeaderSibling(){
if (!document.getElementsByTagName) return false;
var headers = document.getElementsByTagName("h1");
var elem;
for(var i=0;i<headers.length;i++){
elem = getNextElement(headers[i].nextSibling);
elem.className = "intro";
}
}
此时,只需要在CSS中修改.intro类的样式声明即可。
注意:通过className属性设置某个class属性时将替换该元素原来的class属性。
若需要达到追加效果,可编写函数addClass。
function addClass(element,value){
if (!element.className){
element.className = value;
}else{
newClassName = element.className;
newClassName += "";
newClassName += value;
element.className = newClassName;
}
}
对函数进行抽象
我们发现styleHeaderSiblings函数,它仅适用于h1元素,而且className的属性值也是硬编码在函数代码里的,我们通过将这些具体的值转换为这个函数的参数,就可以让它成为一个更通用的函数,将新函数命名为styleElementSiblings,并给它们增加两个参数——tag和theclass。
function styleHeaderSibling(tag,theclass){
if (!document.getElementsByTagName) return false;
var elems = document.getElementsByTagName("tag");
var elem;
for(var i=0;i<elems.length;i++){
headers[i].nextSibling
elem = getNextElement(elems[i].nextSibling);
addClass(elem,theclass)
// elem.style.fontWeight = "bold";
// elem.style.fontSize = "1.4em";
}
}