第2章 基础回顾
在编写程序时,我经常形象思维,这会有助于在头脑中形成与概念对应的等价物。例如,我喜欢把启动一个应用程序想象成航天飞机的发射,因为二者都可能成功或者无法挽回地失败。要想操作DOM,最重要的一点是要知道应该在什么时候启动JavaScript代码。在这一章里,会学习如何用Ext运行JavaScript代码,而且还得保证这些代码在每个浏览器上都能在最恰当的时机初始化。然后再讨论如何通过Ext.Element操作DOM。
你肯定也知道,对DOM的操作是程序员花费时间最多的编码任务。不管是增加一个元素或者是删除一个元素,如果你以前曾用过JavaScript的内置方法来完成这些任务的经历,一定会觉得痛苦不堪。毕竟,截止到目前为止,DHTML作为动态Web页面的核心已经存在很长时间了。
我们还会看到Ext的核心,一个名为Ext.Element的类,这是一个强健的跨浏览器的DOM元素管理工具包。你将学到如何用Ext.Element在DOM中增加或者移除节点,并且还会看到它让这个工作变得多么轻松。
熟悉了Ext.Element类之后,接着就要学习如何通过模板把HTML内容加到DOM中去,我们要深入了解XTemplate的用法,这个类继承自Template,而且你将会学到如何通过它轻松地遍历数据,并能够注入行为调整的逻辑。这会是很有趣的一章。不过,在开始输入代码之前,首先必须要知道的是启动代码的正确方法。
2.1 正确的开始
早前的时候,大多数开发人员所采用的初始化JavaScript的方法是在被加载的HTML页面的< body>标签加上一个onLoad属性:
用这种方法触发JavaScript的确有效,不过对于那些使用了Ajax的Web 2.0站点或者应用程序来说,这并不是一个理想的方法。因为对于不同的浏览器而言,onLoad代码被触发的时间并不完全相同。例如,有的浏览器是在DOM已经准备就绪,而且所有的内容都已经加载完毕、浏览器也已经渲染完毕之后才触发。对于Web 2.0来说,这可不是什么好事,因为一般都希望能在DOM准备就绪之后,但是加载任何图片之前启动代码,从而管理和操作DOM元素。这就需要在时机和结果之间找到最好的平衡点,我喜欢把这个时间点叫做页面加载周期中的“最佳时点”。
在浏览器的世界中,每种浏览器都有它自己的方式判断什么时候DOM节点可以操作。
2.1.1 准备好了再行动
每个浏览器都有自己的原生方案用来检测DOM就绪,不过在不同浏览器间这些方案并不统一。例如,Firefox和Opera会触发DOMContentLoaded事件。IE要求在文档中放一个带defer属性的脚本标签,一旦DOM就绪就会触发它。WebKit不会触发任何事件,不过会把document.readyState属性置成complete,因此必须通过一个循环不断地检查这个属性,然后再触发一个客户事件通知代码DOM已经就绪了。真够乱的吧!
2.1.2 由Ext JS来触发
幸运的是,现在有了Ext.onReady,它解决了这个时机问题,可以用作应用代码的启动基点。Ext JS通过检测代码在哪种浏览器执行,并管理对DOM就绪状态的检测,从而实现了跨浏览器的兼容性,保证了在正确的时间执行代码。
Ext.onReady其实是对Ext.EventManager.onDocumentReady的引用,它接收3个参数:要调用的方法、调用该方法的作用域以及传给该方法的选项。如果初始化方法需要在一个特定的作用域中执行,那么第二个参数,即作用域参数,就会被使用。
获取作用域的处理方法
作用域是许多JavaScript开发人员在他们的职业生涯早期一直纠结的概念。我认为它是每个JavaScript开发人员都要掌握的一个概念。
自己写的那些基于Ext的JavaScript代码可以放在引入Ext JS脚本之后的任何地方。这一点很重要,因为JavaScript文件的请求和加载是同步进行的。如果命名空间中还没有Ext的定义时就调用Ext的方法会导致异常,同时代码也就无法启动。下面就是一个简单的例子,这个例子通过Ext.onReady触发一个Ext的MessgeBox警告窗口:
在这个例子中,把一个所谓的匿名函数作为唯一的参数传给Ext.onReady,一旦DOM就绪,这个匿名函数就会被执行。这里的匿名函数只包含了一行代码,即调用Ext.MessageBox,如图2-1所示。
匿名函数就是没有被任何变量或者任何对象中的键引用的函数。Ext.onReady登记了我们提供的匿名函数,当内部的docReadyEvent事件被触发时,就会执行这个函数。简单地说,事件很像是说明已经发生了什么事情的消息。而监听器是一个被注册的方法,当有事件发生时,这个方法就会被执行,也可以说是被调用。
当Ext的页面加载周期到达了执行我们提供的匿名函数和其他注册的监听器的精确时点(还记得之前提到的最佳时点吗)时,就会触发这个docReadyEvent事件。如果事件这个概念听起来很迷糊,不要担心。事件管理本身就是一个复杂的主题,我们会在第3章介绍。
Ext.onReady的重要性毋庸置疑。所有的示例代码(乃至最终应用程序代码)都必须用这种方法来启动。如果说这个例子中的Ext.onReady还不够详细,那就先记住必须用它来启动代码,而且必须要用下面这种方式来封装示例代码:
既然适应了通过Ext.onReady启动代码,就要花些时间探讨Ext.Element类,它是框架的核心。操作DOM是一个贯穿整个框架的关键主题。