本章内容
- 平稳退化 确保网页在没有JS的情况下也能正常工作。
- 分离JS 把网页的结构和内容与JS脚本的动作行为分开
- 向后兼容性 确保老版本的浏览器不会因为你的JS脚本而死掉
- 性能考虑 确定脚本执行的性能最优
平稳退化
如果正确地使用了JS脚本,就可以让访问者在他们的浏览器不支持JS的情况下仍能顺利地浏览你的网站,这就是平稳退化
JS使用window对象的open()方法来创建新的浏览器窗口。这个方法有三个参数:window.open(url,name,features)
- url新窗口里打开的网页的URL地址
- 新窗口的名字,可以在代码里通过这个名字与新窗口进行通信。
- 以逗号分隔的字符串。其内容是新窗口的各种属性。
function popUp(winURL) {
window.open(winURL,"popUp","width=320,height=480");
}
调用popUp函数的一个办法就是使用伪协议。
真协议用来在因特网上的计算机之间传递数据包,如http协议、ftp协议。伪协议是一种非标准化的协议。“javascript:”伪协议让我们通过一个链接来调用JS函数。
具体做法:
<a href="javascript:popUp('http://www.baidu.com/');">Example</a>
这条语句在支持“javascript:”伪协议的浏览器中运行正常,较老的浏览器则会尝试打开链接失败,支持这种伪协议但禁用了JS功能的浏览器会什么也不做。
总之,在html文档里通过javascript:伪协议调用JavaScript代码的做法非常不好。
内嵌的事件处理函数
把onclick事件处理函数作为属性嵌入a标签,改处理函数将在onclick事件发生时调用图片切换函数。
<a href="#" onclick="popUp('http://www.example.com');return false;">Example</a>
因为在上面这条HTML指令里使用了return false语句,这个链接不会被真的打开。“#”符号是一个仅供文档内部使用的链接符号。把href属性值设置为“#”只是为了创建一个空链接。实际工作全部由onclick属性负责完成。
但是上面的技巧都不能平稳的退化,如果用户已经禁用了浏览器的JS功能,这样的链接毫无用处。
具体到popUp()函数,为其中的JS代码预留出退路很简单。在链接里把href属性设置为真实存在的URL地址,让它成为一个有效的链接。
<a href="http://www.example.com/" onclick="popUp('http://www.example.com';return false;)">Example</a>
//-------------用this简化一下-------------//
<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>
在本书此前介绍的所有技巧当中,这个技巧最有用,但是它还有改进的余地。最明显的不足时:每当需要打开新窗口时,就不得不把一些JS代码嵌入标记文档中。如果能把事件处理函数在内的所有JS代码全都放在外部文件里,这个技巧将更加完善
向CSS学习
CSS是一项了不起的技术。CSS可以让人们对网站设计工作中的各个方面做出严格细致的控制。
标记良好的内容就是一切
PS:上面这句话深有感触。
分离JS
JS语言不要求事件必须在HTML文档里处理。我们可以在外部JS文件里吧一个事件添加到HTML文档中的某个元素上。element.event=action...
关键是怎样才能把应该获得这个事件的元素确定下来。这个问题可以利用class或者id来解决。
如果想把一个事件添加到某个带有特定id属性的元素上,用getElementById就可以解决问题:getElementById(id).event=action。如果事件涉及到多个元素,我们可以用getElmentsByTagName和getAttribute把事件添加到有着特定属性的一组元素上。
具体步骤:
- 把文档里的所有链接全放入一个数组里。
- 遍历数组。
- 如果某个链接的class属性等于popup,就表示这个链接在被点击时应该调用popUp()函数。
于是,
- 把这个链接的href属性值传递给popUp()函数;
- 取消这个链接的默认行为,不让这个链接把访问者带离当前窗口。
var links=document.getElementByTagName("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;
}
}
}
如果把上面这段代码存入外部JS文件中,它们将无法正常运行。因为代码的第一行是var links=document.getElementsByTagName("a");这句话将在JS文件被加载时立刻执行。如果JS文件是从HTML文档的< head>部分用<script>标签调用的,它将在HTML文档之前加载到浏览器里。同样,如果标签位于文档底部</body>之前,就不能保证哪个文件最先结束加载(浏览器可能加载多个),因为脚本加载时文档可能不完整,所以模型也不完整,没有完整的DOM,getElementByTagName等方法就不能正常工作。必须让这些代码在HTML文档全部加载到浏览器之后马上开始执行。
HTML文档加载完毕时将触发一个事件,文档将被加载到一个浏览器窗口里,document对象又是window对象。当window对象触发onload事件时,document对象已经存在
window.onload=prepareLinks;
funciton 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;
}
}
}
}
向后兼容
对象检测
判断浏览器是否对DOM支持,最简单的解决方案是,检测浏览器对JS的支持程度。解决方案:只要把某个方法打包在一个if语句中,就可以根据这条if语句的条件表达式的求值结果是true还是false来决定采取怎样的行动。这种检测称为对象检测。
例如,如果有一个使用了getElementById()方法的函数,就可以在调用getElementById()方法之前先检查用户所使用的浏览器是否支持这个方法。**在使用对象检测时,一定要删掉方法后面的圆括号,如果不删掉,测试的将是方法的结果。无论方法是否存在。
function myFunction(){
if(document.getElementById){
statements using getElementById
}
}
为了避免上面的方法,增加逻辑的深度,可以使用下面的方式。
if(!getElementById){
return false;
}
//------------如果要检测多个方法或着属性是否存在,可以使用“逻辑或”
if(!getElementById||!getElementByTagBName){
return false;
}
上面的例子增加JS是否支持DOM的语句如下:
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;
}
}
}
}
浏览器嗅探技术
浏览器嗅探 指通过提取浏览器供应商提供的信息来解决向后兼容问题。从理论上讲,可以通过JS代码检索关于浏览器品牌和版本的信息,这些信息可以用来改善JS脚本代码的向后兼容性。
PS:浏览器嗅探技术充满风险,逐渐被对象检测技术所取代。主要是两个原因,一个是浏览器会撒谎,你无法获得准确的版本或者品牌信息。第二是浏览器嗅探器脚本是对版本信息进行精确匹配,版本信息变化太快,脚本所做的修好会比较多。
性能考虑
尽量少访问DOM和尽量减少标记
访问DOM方式对脚本性能会产生非常大的影响。不管什么时候,只要查询DOM中某些元素,浏览器都会搜索整个DOM树,从中查找可能匹配的元素。
另一个需要注意的地方,就是要尽量减少文档中的标记数量。过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树以查找特定元素的时间。
合并和放置脚本
将多个js文件合并到一个文件中,这样就可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。
把所有script标签都放到文档的末尾,body标记之前,就可以让页面变得更快。
压缩脚本
压缩脚本可以加快加载速度。
所谓压缩脚本,指的是把脚本文件中不必要的字节,如空格和注释,统统删掉,从而达到压缩文件的目的。精简后的代码虽然不容易看懂,却能大幅减少文件大小。多数情况下,你应该有两个版本。一个是工作副本,可以修改代码并添加注释;另一个是精简副本,用于放在站点上。通常为了将精简版本与非精简版本区分开,最好在精简副本的文件名上加上min字符。
推荐的几个代表性的代码压缩工具:
- Douglas Crockford的JSMin(http://www.crockford.com)
- 谷歌的Closure Compiler(http://closure-compiler.appspot.com/home)