编写分离式(unobstrusive)代码意味着对HTML内容的完全分离:数据来自服务器端,javascript代码用来动态化和交互。这种分离的好处是在不同浏览器之间使用是可以完全降级或升级运行,对于高级特性浏览器提供更丰富的交互,不支持高级特性的浏览器可以降级运行其所支持的部分。
一、DOM
DOM是表达XML文档的应用最广泛的方式,虽然可能未必是最快或者最轻量级和最易使用的,但是大部分web开发语言都提供了其实现。javascript最终的操作都是和网页里的HTML元素进行交互,而HTML是XML的一个子集,因此DOM是简化操作的出色工具,是开发分离式javascript代码的第一步,无非就是提供了以下几个简化的操作:获取或修改特定HTML元素、对元素的属性进行修改、绑定事件及编写处理函数。
1、概念
DOM(文档对象模型)是W3C制定的一个表达XML文档的标准,可以把XML的DOM表达方式看做一棵导航树,一切术语都与家谱术语类似(parent、child、sibling)。节点包含了nodeType、nodeValue、nodeName,每个节点有都包含指向父节点、子节点、相邻兄弟节点的指针。
2、处理空格
使用while循环查找是否为空的节点,并测试节点类型nodeType是否为1、2、3等,否则就删除继续查找下一个节点。
3.、获取和查找元素
getElementById("id"):从所有元素中查找属性ID为id的元素,速度很快,定位准确,但是不能出现ID同名的元素。
getElementByTagName("tag"):运行于任何元素下,找出标签名称为tag的节点列表Nodelist,类似于数组,但是不支持push、pop、shift等javascript数组操作方法。
innerHTML:用来设置或获取元素类的html,短小的代码使用这个特性很快捷,但是会有一些浏览器不同的bug,IE中返回的都是大写的元素字符,基于Mozilla的浏览器不会返回<style>元素等。
innerText:方便获取元素下的所有文本类容,但是在由于在一些流行的浏览器不兼容,因此有如下的替代方法
function text(e){ var t = ""; e = e.childNodes || e; for (var j = 0; j < e.length; j++){ t += e[j].nodeType != 1 ? e[j].nodeValue : text(e[j].childNodes); return t; } }className:使用类名查找元素,这是jquery提供的强大的选择器,同时也有css选择器,公开库有cssQuery。
XPath:这是一种强大的纯粹的XML定位方式,W3C的标准,DOM的实现也是肯定基于XPath,与CSS选择器相比表达式相对冗长,当时功能更加强大。
4、等待HTML DOM加载
浏览器渲染和操作的顺序如下:
html解析完毕 ——> 外部脚本和样式表加载 ——> 脚本在文档内解析并执行 ——> HTML DOM完全构造起来 ——> 图片和外部内容加载 ——> 网页加载完成
网页头部的外部文件加载后会在HTML真正构造起来之前执行,这对于某些重要的情形是不能满足要求的。补救如下:
- 等待整个页面加载:window.onload事件绑定一个函数在页面完全加载后触发。
- 等待大部分DOM加载:行内的脚步在DOM构造后就可以立即执行,执行到该位置上的脚步才真正执行,也就是在页面中途嵌入的行内脚步只能访问该位置之前的DOM。因此可以在body结尾标签之前才执行脚本。
- 判断DOM合适加载完毕:监听DOM加载状态,是最有效的但是也是实现起来最复杂的。可以绑定windows事件那样简单又能获得行内脚步执行那样的速度。检查DOM元素和方法是否存在:检查要点document、document.getElementById等函数、document.body等或其他特定元素。
二、事件
事件是把所有东西粘在一起的胶水,DOM和javascript事件的结合是现代web应用程序的根基。主要有以下几种类型事件:
- 鼠标事件:追踪鼠标定位、点击事件
- 键盘事件:追踪键盘敲击和上下文
- UI事件:页面的某一方面是否覆盖了另一方面
- 表单事件:表单输入元素上
- 加载和错误事件:监听自身加载状态
javascript目前不存在线程,完全是异步。代码的运行由其他动作触发,绑定好一个回调函数到特定事件即可。最近的就是模拟线程的就是使用setInterval加递归模拟。事件处理的阶段包括从body元素向下到发生事件的元素的捕获阶段和从发生事件的元素到最外层元素的冒泡阶段,组织冒泡可以为负责的程序提供益处,同时取消浏览器的默认行为会在需要处理的95%的情况中有效,不同的浏览器处理不同,因此是分离式DOM脚本编程的重要部分。
- 传统绑定:对象.事件 = function (){....} 有点事简单和稳定,不同浏览器运作一致,this关键字引用当前元素。缺点是旨在事件冒泡中允许,而非捕获和冒泡,同时一个元素一次只能绑定一个事件处理函数
- DOM绑定:W3C提供的标准是addEventListener函数,提供三个参数:事件名称、处理函数、启用禁用事件捕获的布尔标记。优点是支持设置捕获和冒泡阶段,this指向当前元素,事件对象总是可以通过处理函数的第一个参数获取,同时可以为一个元素绑定多个事件而不会覆盖先前绑定的事件。
- IE绑定:可以绑定多个事件,但是仅支持冒泡阶段,this指向了window对象,不是当前元素,事件对象仅存在window.event参数中。同时必须以on+事件名的方式,仅IE可用。
三、javascript与CSS
在DOM和事件的交互基础上产生了DHTML,实质是javascript与DOM元素上的CSS属性之间的交互。
上述所有问题的讨论都是为了实现分离式脚本编程以适应不同浏览器而做到预留退路。首先应用程序的所有功能都要检查(if(document && document.getElementById)),其次是使用DOM遍历查找的通用方法来快速访问文档中的元素,最后是使用DOM和attachEvent/addEvenetListener函数为元素添加事件处理函数,<a href="#" onclick="dosth()...">...</a>这样的代码是非常不好的。
- javascript禁用:如果禁用了javascript,所有的页面都要能工作,最明显的就是a链接的href属性和onclick事件。
- 链接不依赖javascript:所有的链接都不应该有破坏性,通过链接可以删除、编辑或者修改任何用户数据的话都应该用表单实现。
- 监听css合适禁用
- 事件的亲和力:确保事件在不适用鼠标的情况下依然具备亲和力,可以对每个人都有好处。