JavaScript CSS-DOM技术

来源:互联网 发布:linux if语句的用法 编辑:程序博客网 时间:2024/05/16 07:13
本文来自学习JavaScript DOM编程艺术一书时的笔记和总结等。

CSS-DOM技术针对的是如何得到和设置style对象的各种属性,而style对象本身又是文档中的每个元素节点都具备的属性。不过,只要有可能,就应选择更新className属性,而不是去更新style对象的有关属性。如果想改变某个元素的呈现效果,使用CSS;如果想改变某个元素的行为,使用DOM;如果你想根据某个元素的行为去改变它的呈现效果,请运用你的智慧,在这个问题上没有标准答案。
接下来,将主要学习CSS-DOM的以下几个技术知识:
  • 根据元素在节点树里的位置设置它们的样式
  • 遍历一个节点集合设置有关元素的样式
  • 在事件发生时设置有关元素的样式

1、关于网页的分层知识

  • 结构层,使用(X)HTML去搭建文档的结构;
  • 表示层,使用CSS去设置文档的呈现效果;
  • 行为层,使用DOM脚本去实现文档的行为。

2、style属性

  • 文档的每个元素节点都有一个style属性,style属性包含着元素的样式。样式都存放在这个style对象的属性里。
  • 查询这个属性将返回一个对象而不是一个简单的字符串。
  • style对象的各个属性都是可读写的。

一个样例标记文件:
<p id="example" style="color: grey; font-family: 'Arial',sans-serif;">An example of a paragraph</p>

访问element.style.color可以获得style对象的color属性;
访问element.style.fontFamily可以获得style对象的font属性;
注:当你需要引用一个中间带减号的CSS属性时,DOM要求你使用驼峰命名法。

需要注意的一点是:DOM style属性不能用来检索在外部CSS文件里声明的样式,style对象只包含在HTML代码里用style属性声明的样式。
但如果你是用DOM设置的样式,就可以再用DOM把它们检索出来。

可以使用赋值操作来更新元素的样式:
element.style.property = value例如:para.style.color = "black";para.style.font = "2em 'Times'serif";
注:上面语句是同时赋值了fontSize和fontFamily两个属性

3、通过CSS声明样式的方法主要有三种

(1) 为标签元素统一地声明样式
p {    font-size: 1em;}
(2) 为有特定class属性的所有元素统一声明样式
.fineprint {    font-size: .8em;}
(3) 为有独一无二的id属性的元素单独声明样式
#intro {    font-size: 1.2em;}
(4) 还有两类变种方法
可以为有类似属性的多个元素声明样式:
input[type*="text"] {    font-size: 1.2em;}
在现代浏览器中,可以根据元素的位置来声明样式:
p:first-of-type {    font-size: 2em;font-weight: bold;}

CSS2引入了很多位置相关的选择器,例如:first-child和:last-child
CSS3则定义了:nth-child()和:nth-of-type()之类的位置选择器。在CSS3中还可以使用h1~*选择器为所有h1元素的下一个同辈元素声明样式。
问题:仍然有很多的浏览器,不支持CSS3的这些位置选择器功能。

4、根据元素在节点树里的位置来使用DOM脚本设置样式

目前,CSS还无法根据元素之间的相对位置关系人找出某个特定的元素。但这对于DOM却是轻而易举的。
样例:定义一个名为styleHeaderSiblings的JS函数,来为文档中所有h1元素后的那个元素设置一个特殊的样式。
标记文件story.html
<!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>Now you get the nitty-gritty of the story.</p>    <p>The most important information is delivered first.</p>    <h1>Extra Extra!</h1>    <p>Further developments are unfolding.</p>    <p>You can read all about it here.</p></body></html>
页面浏览效果如下图所示:

我们现在编写一个名为styleHeaderSiblings.js脚本文件,以实现对h1标题后第一个元素节点的样式设置。
function sytleHeaderSiblings() {    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.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 null;}addLoadEvent(sytleHeaderSiblings);

将该js函数加载到标记文件中并随浏览器打开自动被调用,效果如下:

5、使用DOM技术根据某种条件反复设置某种样式

这种情况最为典型的应用安全是,对一个表格让表格里的行交替改变它们的颜色,从而形成斑马线效果,便于阅读。
如果浏览器支持CSS3的话,有一种非常简便的方法如下:
tr:nth-child(odd) { background-color:#ffc; }tr:nth-child(even) { background-color:#fff; }

鉴于仍然有很多浏览器对CSS3的支持不够好,显然使用JavaScript处理这种重复性任务是一个不错的选择。
可以编写一个函数来为表格添加斑马线效果,只要隔行设置效果就行了:
  • 把文档里的所有table元素找出来;
  • 对每个table元素,创建odd变量并把它初始化为false;
  • 遍历这个表格里的所有数据行;
  • 如果变量odd的值是true,设置样式并把odd变量修改为false;
  • 如果变量odd的值是false,不设置样式,但把odd变量修改为true。

以下是实现这个样例的标记文件、css文件和js文件。
(1) 标记文件itinerary.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="utf-8" />    <title>Cities</title>    <link rel="stylesheet" media="screen" href="styles/format.css" />    <script type="text/javascript" src="scripts/addLoadEvent.js"></script>    <script type="text/javascript" src="scripts/stripeTables.js"></script>    <script type="text/javascript" src="scripts/highlightRows.js"></script></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="California">CA</abbr></td>        </tr>        </tbody>    </table></body></html>

(2) css样式文件format.css
body {    font-family: "Helvetica","Arial",sans-serif;    background-color: #fff;    color: #000;}table {    margin: auto;    border: 1px solid #699;}caption {    margin: auto;    padding: .2em;    font-size: 1.2em;    font-weight: bold;}th {    font-weight: normal;    font-style: italic;    text-align: left;    boder: 1px dotted #699;    background-color: #9cc;    color: #000;}th,td {    width: 10em;    padding: .5em;}

(3) js函数stripeTables
function stripleTables() {    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(stripleTables);

此时套用了css样式,并经由DOM方法加工后的表格呈现出了下面的效果。

6、使用DOM根据响应事件改变元素的样式

在css做得不是很好的领域,DOM可以解决很多问题。
如果是要让链接在鼠标指针悬停在其上时改变颜色,就应该使用css伪类实现:
a:hover {    color: #c60;}
css伪类:hover已经得到了绝大多数浏览器的支持,至少是在处理改变链接的样式时是这样。
但是如果还想让鼠标指针悬停在其它元素上时改变样式,支持这种用法的浏览器就很少了。不过,DOM仍然可以很容易得做到这一点。

下面的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);

7、className属性
在前面的例子中,一直在使用DOM直接设置或修改样式。这种让行为层干表示层的活,并不是理想的工作方式。
这里还有一种简明的解决方案:与其直接使用DOM改变某个元素的样式,不如通过js代码去更新这个元素的class属性。

className是一个可读/可写的属性:element.className = value

以下通过对前面的两个样例进行优化,来应用className属性。
(1) 优化第一步:改造styleHeaderSiblings函数
定义一个外部样式:
.intro {    font-weight: bold;    font-size: 1.2em;}
js函数改造为:
function sytleHeaderSiblings() {    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的样式声明。

(2) 优化第二步:封装一个addClass函数
在上一步中通过className属性设置某个样式的class属性时,是完全替换原有样式,而不是追加。如果我们需要的是再叠加一种新样式,则需要定义一个函数,做一些处理工作。
function addClass(element,value) {    if (!element.className) {        element.className = value;    } else {        newClassName = element.className;        newClassName+= " ";        newClassName+= value;        element.className = newClassName;    }}
注:如果元素原来未指定样式,则直接进行赋值;否则,就把一个空格和新样式追加到className属性上去。

js函数继续改造为:
function sytleHeaderSiblings() {    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)        addClass(elem,"intro");    }}

也使用addClass函数改造一下stripeTables这个斑马线函数:
先增加一个样式声明
.odd {    background-color: #ffc;}

function stripleTables() {    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) {                addClass(rows[j],"odd");                odd = false;            } else {                odd = true;            }        }     }}

(3) 优化第三步:对函数继续进行抽象
在前两步的优化尝试中仍然是对样式进行的硬编码,写在函数代码里的。下面对styleElementSiblings函数转换为一个更通用的函数,为其增加两个参数——tag和theclass。使其可以灵活得按设计需求决定参数取值。
function sytleHeaderSiblings(tag,theclass) {    if (!document.getElementsByTagName) return false;    var headers = document.getElementsByTagName(tag);    var elem;    for (var i=0; i<headers.length; i++) {        elem = getNextElement(headers[i].nextSibling);        addClass(elem,theclass);    }}//确保获取到的下一个是元素节点function getNextElement(node) {    if (node.nodeType == 1) {        return node;    }    if (node.nextSibling) {        return getNextElement(node.nextSibling);    }    return null;}addLoadEvent(function() {    sytleHeaderSiblings("h1","intro");});

到这一步为止,所有我们能做的优化工作终于都做完了。通过对一个元素样式设置函数的渐进优化,我们最终得到了一个行为和样式分离,又避免了直接在代码中硬编码的实现结果。

原创粉丝点击