[笔记6]JavaScript DOM编程艺术_最佳实践

本章内容

  • 平稳退化 确保网页在没有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字符。

推荐的几个代表性的代码压缩工具:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容