首页 > 代码库 > JavaScript DOM 编程艺术(第2版)读书笔记(5)

JavaScript DOM 编程艺术(第2版)读书笔记(5)

最佳实践

平稳退化

网站的访问者完全有可能使用的是不支持Javascript的浏览器,还有一种可能是虽然浏览器支持Javascript,但用户已经禁用它了。如果没有考虑到这种情况,人们在访问你们的网站时就有可能遇到各种各样的麻烦,并因此不再来访问你们的网站。

如果正确使用了Javascript脚本,就可以让访问者在他们的浏览器不支持Javascript的情况下仍能顺利地浏览你的网站。这就是所谓的平稳退化,就是说,虽然某些功能无法使用,但最基本的操作仍能顺利完成。

下面来看一个在新窗口中打开一个链接的例子:

function popUp(winURL){

  window.open(winURL,"popup","width=320, height=480");

}

<a href="http://www.mamicode.com/#" onclick="popUp(‘http://www.example.com/‘); return false;">Example</a>

在这个实例中,实际工作都由onclick属性负责完成,不能平稳退化。

在链接里把href属性设置为真实存在的URL地址,让它成为一个有效的链接:

<a href="http://www.example.com/" onclick="popUp(‘http://www.example.com/‘); return false;">Example</a>

或者

<a href="http://www.example.com/" onclick="popUp(this.getAttribute(‘href‘)); return false;">Example</a>

或者

<a href="http://www.example.com/" onclick="popUp(this.href); return false;">Example</a>

这三种方法都是可以的。

在把href属性设置为真实存在的URL地址之后,即使Javascript已被禁用,这个链接也是可用的。虽然这个链接在功能上打了点折扣(因为它没有打开一个新窗口),但是它并没有彻底失效。这是一个经典的“平稳退化”的例子。

这个技巧最明显的不足是:每当需要打开新的窗口时,就不得不把Javascript代码嵌入标记文档中。如果能把包括事件处理函数在内的所有Javascript代码全部放在外部文件里,这个技巧将更加完善。

向CSS学习

我们经常会遇到一些几乎每个元素都带有style属性的Web文档,而这是CSS技术最缺乏效率的用法之一。真正能从CSS技术获益的方法,是把样式全部转移到外部文件中去。

文档结构和文档样式的分离可以确保网页都能平稳退化。

所谓“渐进增强”就是用一些额外的信息层去包裹原始数据。按照“渐进增强”原则创建出来的网页几乎都符合“平稳退化”原则。

类似于CSS,Javascript和DOM提供的所有功能也应该构成一个额外的指令层。类似于使用style属性,在HTML文档里使用诸如onclick之类的属性也是一种既没有效率又容易引发问题的做法。如果我们用一个“挂钩”,就像CSS机制中的class或者id属性那样,把Javascript代码调用行为与HTML文档的结构和内容分离开,网页就会健壮得多。那么怎么把上面示例中的Javascript代码分离出来呢?

<a href="http://www.example.com/" class="popup">Example</a>

在外部的Javascript文件里把一个事件添加到HTML文档中的某个元素上:

element.event = action...

关键是怎么把应该获得这个事件的元素确定下来。具体步骤如下:

(1)把文档里的所有链接全放入一个数组里;

(2)遍历数组;

(3)如果某个链接的class等于popup,就表示这个链接在被点击时应该调用popUp()函数。

下面是实现上述步骤的Javascript代码:

var links = document.getElementsByTagName("a");

for(var i=0;i<links.length;i++){

  if(links[i].getAttribute("class")=="popup"){

    links[i].onclick = function(){

      popUp(this.getAttribute("href"));

      return false;

    }  

  }

}

还有个问题需要解决:如果把这段代码存入外部Javascript文件,它将无法正常运行。因为这段代码的第一行是:

var links = document.getElementsByTagName("a");

这条语句将在Javascript文件被加载时立刻执行。如果Javascript文件是从HTML文档的<head>部分用<script>标签调用的,它将在HTML文档之前加载到浏览器里。同样如果<script>标签位于文档底部</body>之前,就不能保证哪个文件最先结束加载(浏览器可能一次加载多个)。因为脚本加载时文档可能不完整,所以模型也不完整。没有完整的DOM,getElementsByTagName等方法就不能正常工作。

必须让这些代码在HTML文档全部加载到浏览器之后马上开始执行。还好,HTML文档全部加载完毕时将触发一个事件,这个事件有它自己的事件处理函数。我将把我的Javascript代码打包在prepareLinks函数里,并将这个函数添加到window对象的onload事件上去。这样一来,DOM就可以正常工作了:

window.onload = prepareLinks;

function prepareLinks(){

  var links = document.getElementsByTagName("a");

  for(var i=0;i<links.length;i++){

   if(links[i].getAttribute("class")=="popup"){

     links[i].onclick = function(){

       popUp(this.getAttribute("href"));

       return false;

      }  

    }

  }

}

别忘记把popUp函数也保存到那个外部Javascript文件里去。

向后兼容

你的网站的访问者很可能未启用Javascript功能,而且不同的浏览器对Javascript的支持程度也不一样。绝大多数浏览器都能或多或少地支持Javascript,而绝大多数现代的浏览器对DOM的支持都非常不错。但比较古老的浏览器却很可能无法理解DOM提供的方法和属性。因此,即使某位用户在访问你的网站时使用的是支持Javascript的浏览器,某些脚本也不一定能正常工作。

针对这一问题的最简单的解决方案是,检测浏览器对Javascript的支持程度。

if(!getElementsByTagName || !getElementById) return false;

按照这一思路,在用来把onclick事件添加到链接上去的网页加载脚本里插入一条if语句。

window.onload = prepareLinks;

function prepareLinks(){

  if(!document.getElementsByTagName) return false;

  var links = document.getElementsByTagName("a");

  for(var i=0;i<links.length;i++){

   if(links[i].getAttribute("class")=="popup"){

     links[i].onclick = function(){

       popUp(this.getAttribute("href"));

       return false;

      }  

    }

  }

}

虽然只是一条if语句,但它可以确保那些“古老”的浏览器不会因为我的脚本代码而出问题。这么做是为了让脚本有良好的向后兼容性。

浏览器嗅探技术

在Javascript脚本代码里,在使用某个特定的方法或属性之前,先测试它是否真实存在是确保向后兼容性最安全和最可信的方法,但它并不是唯一的方法。在浏览器市场群雄逐鹿的那个年代,一种称为浏览器嗅探的技术曾经非常流行。

“浏览器嗅探”指通过提取浏览器供应商提供的信息来解决向后兼容问题。从理论上讲,可以通过Javascript代码检索关于浏览器品牌和版本的信息,这些信息可以用来改善Javascript脚本代码的向后兼容性,但这是一种风险非常大的技术。

首先,浏览器有时会“撒谎”。因为历史原因,有些浏览器会把自己报告成为另外一种浏览器,还有一些浏览器允许用户任意修改这些信息。

其次,为了适用于多种不同的浏览器,浏览器嗅探脚本会变得越来越复杂。如果想让浏览器嗅探脚本能够跨平台工作,就必须测试所有可能出现的供应商和版本号组合。这是一个无穷尽的任务,测试的组合情况越多,代码就越复杂和冗长。

最后,许多浏览器嗅探脚本在进行这类测试时要求浏览器的版本号必须得到精确的匹配。因此,每当市场上出现新版本时,就不得不修改这些脚本。

令人感到欣慰的是,充满着风险的浏览器嗅探技术正在被更简单也更健壮的对象检测技术所取代。

性能考虑

尽量少访问DOM和尽量减少标记:

不管什么时候,只要是查询DOM中的某些元素,浏览器就会搜索整个DOM树,从中查找可能匹配的元素;

另外,过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树以查找特定元素的时间。

合并和放置脚本:

把脚本都合并到一个脚本文件中,可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。

把<script>标签放到别的地方并不是问题,但把所有<script>标签放到文档的末尾,</body>标记之前,就可以让页面变得更快。即使这样,在加载脚本时,window对象的load事件依然可以执行对文档进行的各种操作。

压缩脚本:

所谓压缩脚本,指的是把脚本文件中不必要的字节,如空格和注释,统统删除,从而达到“压缩”文件的目的。好在,有很多工具都可以替你来做这件事。有的精简程序甚至会重写你的部分代码,使用更短的变量名,从而减少整体文件大小。精简后的代码虽然不易看懂,却能大幅减少文件大小。多数情况下,你应该有两个版本,一个是工作副本,可以修改代码并添加注释;另一个是精简副本,用于放在站点上。通常,为了与非精简版本区分开,最好在精简副本的文件名中加上min字样。

下面是推荐给读者的几个有代表性的代码压缩工具:

Douglas Crockford 的JSMin

雅虎的YUI Compressor

谷歌的Closure Compiler

JavaScript DOM 编程艺术(第2版)读书笔记(5)