处理 AIR 中与 HTML 相关的事件

Adobe AIR 1.0 和更高版本

利用事件处理系统,程序员可以十分方便地响应用户输入和系统事件。Adobe® AIR® 事件模型不仅方便,而且符合标准。事件模型基于文档对象模型 (DOM) 第 3 级事件规范,是业界标准的事件处理体系结构,为程序员提供了强大而直观的事件处理工具。

HTMLLoader 事件

HTMLLoader 对象调度以下 Adobe® ActionScript® 3.0 事件:

事件

说明

htmlDOMInitialize

在创建 HTML 文档时调度,调度时未分析任何脚本或未将 DOM 节点添加到页面。

complete

在为响应加载操作而创建 HTML DOM 后,紧接在 HTML 页面中的 onload 事件后调度。

htmlBoundsChanged

contentWidth 和/或 contentHeight 属性发生了变化时调度。

locationChange

在 HTMLLoader 的 location 属性发生了变化时调度。

locationChanging

由于用户导航、JavaScript 调用或重定向,在 HTMLLoader 的位置发生变化前调度。当您调用 load()loadString()reload()historyGo()historyForward()historyBack() 方法时未调度 locationChanging 事件。

调用所调度事件对象的 preventDefault() 方法会取消导航。

如果系统浏览器中打开某个链接,则不会调度 locationChanging 事件,因为 HTMLLoader 不会改变位置。

scroll

只要 HTML 引擎更改滚动位置,便会调度此事件。Scroll 事件的引发可能是由于导航到页面中的锚记链接(# 链接),也可能是由于调用 window.scrollTo() 方法。在文本输入或文本区域中输入文本也可能会引发 scroll 事件。

uncaughtScriptException

当在 HTMLLoader 中发生 JavaScript 异常,并且在 JavaScript 代码中未捕获到该异常时调度。

AIR 类-事件处理与 HTML DOM 中其他事件处理的不同之处

HTML DOM 提供了几种不同的方法来处理事件:

  • 在 HTML 元素的开始标签中定义 on 事件处理函数,如下所示:

    <div id="myDiv" onclick="myHandler()">
  • 回调函数属性,例如:

    document.getElementById("myDiv").onclick 
  • 您使用 addEventListener() 方法注册的事件侦听器,如下所示:

    document.getElementById("myDiv").addEventLister("click", clickHandler)

不过,由于运行时对象不会出现在 DOM 中,因此您只能通过调用 AIR 对象的 addEventListener() 方法来添加事件侦听器。

与在 JavaScript 中一样,由 AIR 对象调度的事件可以与默认行为关联起来。(默认行为 是 AIR 作为特定事件的正常后果而执行的动作。)

由运行时对象调度的事件对象是 Event 类或其某一个子类的实例。事件对象不但存储有关特定事件的信息,还包含便于操作此事件对象的方法。例如,如果 AIR 在异步读取文件时检测到 I/O 错误事件,则会创建用来表示该特定 I/O 错误事件的事件对象(IOErrorEvent 类的实例)。

无论何时编写事件处理函数代码,该代码都采用相同的基本结构:

function eventResponse(eventObject) 
{ 
    // Actions performed in response to the event go here. 
} 
 
eventTarget.addEventListener(EventType.EVENT_NAME, eventResponse);

此代码完成两项任务。首先,它定义一个处理函数,这是指定为响应事件而要执行的动作的方法。接下来,它调用源对象的 addEventListener() 方法,实际上就是为指定事件订阅该函数,以便当该事件发生时,执行处理函数动作。当事件实际发生时,事件目标将检查其向事件侦听器注册的所有函数和方法的列表。然后,它依次调用每个函数或方法,同时将事件对象作为参数传递。

默认行为

开发人员通常负责编写响应事件的代码。但在某些情况下,行为通常与某一事件关联,使得 AIR 会自动执行该行为,除非开发人员添加了取消该行为的代码。由于 AIR 会自动表现该行为,因此这类行为称为默认行为。

例如,当用户单击应用程序窗口的关闭框时,普遍期待窗口关闭,因此该行为被内置到 AIR 中。如果您不希望该默认行为发生,可以使用事件处理系统来取消它。当用户单击某个窗口的关闭框时,表示该窗口的 NativeWindow 对象将调度 closing 事件。若要防止运行时关闭该窗口,您必须调用已调度的事件对象的 preventDefault() 方法。

并非所有默认行为都可以被阻止。例如,当 FileStream 对象将数据写入某个文件时,运行时将生成 OutputProgressEvent 对象。无法阻止的默认行为是:用新数据更新该文件的内容。

许多类型的事件对象没有关联的默认行为。例如,在读取了 MP3 文件中的足量数据后,Sound 对象会调度 id3 事件以提供 ID3 信息,但没有与其关联的默认行为。Event 类及其子类的 API 文档列出了每一类型的事件,并说明所有关联的默认行为,以及是否可以阻止该行为。

注: 默认行为仅与运行时直接调度的事件对象关联,对于通过 JavaScript 以编程方式调度的事件对象,不存在默认行为。例如,可以使用 EventDispatcher 类的方法调度事件对象,然而调度事件并不会触发默认行为。

事件流

在 AIR 中运行的 SWF 文件内容使用 ActionScript 3.0 显示列表体系结构来显示可视内容。ActionScript 3.0 显示列表为在父级显示对象和子级显示对象之间传播的 SWF 文件内容中的内容和事件(如鼠标单击事件)提供父子关系。HTML DOM 有它自己的只遍历 DOM 元素的独立事件流。当为 AIR 编写基于 HTML 的应用程序时,您主要是使用 HTML DOM 而不是 ActionScript 3.0 显示列表,因此您通常可以忽略 AIR 参考文档中出现的有关事件阶段的信息。

Adobe AIR 事件对象

在事件处理系统中,事件对象有两个主要用途。首先,事件对象通过将特定事件的有关信息存储在一组属性中来表示实际事件。其次,事件对象包含一组方法,可用于操作事件对象和影响事件处理系统的行为。

AIR API 定义了 Event 类,该类用作 AIR API 类调度的所有事件对象的基类。Event 类定义所有事件对象共有的一组基本属性和方法。

若要使用 Event 对象,务必要先了解 Event 类的属性和方法以及 Event 类的子类存在的原因。

了解 Event 类的属性

Event 类定义了提供有关事件的重要信息的多个只读属性和常量。以下项尤为重要:

  • Event.type 描述事件对象表示的事件的类型。

  • Event.cancelable 是一个布尔值,用于报告与事件关联的默认行为(如果有)是否可以取消。

  • 事件流信息包含在其余的属性中,仅当在 AIR 中的 SWF 内容中使用 ActionScript 3.0 时才有用。

事件对象类型

每个事件对象都有关联的事件类型。数据类型以字符串值的形式存储在 Event.type 属性中。知道事件对象的类型是非常有用的,这样您的代码就可以区分不同类型的对象。例如,下面的代码注册一个 fileReadHandler() 侦听器函数以响应 myFileStream 调度的 complete 事件:

myFileStream.addEventListener(Event.COMPLETE, fileReadHandler);

AIR Event 类定义许多类常量(如 COMPLETECLOSINGID3),以表示运行时对象调度的事件的类型。这些常量列在针对 HTML 开发人员的 Adobe AIR API 参考的“Event 类”页面中。

事件常量提供了引用特定事件类型的简便方法。使用常量(而不是字符串值)可帮助您更快地识别拼写错误。如果您的代码中拼错了某个常量名,则 JavaScript 分析器将捕获到该错误。而如果您拼错了事件字符串,将会为永远都不会调度的一种事件注册事件处理函数。因此,在添加事件侦听器时,建议使用下面的代码:

myFileStream.addEventListener(Event.COMPLETE, htmlRenderHandler);

而不是使用:

myFileStream.addEventListener("complete", htmlRenderHandler);

默认行为信息

代码可通过访问 cancelable 属性来检查是否可以阻止任何给定事件对象的默认行为。cancelable 属性保存着一个布尔值,用于指示是否可以阻止默认行为。您可以使用 preventDefault() 方法阻止或取消与少量事件关联的默认行为。有关详细信息,请参阅取消事件默认行为

了解 Event 类的方法

有三种类别的 Event 类方法:

  • 实用程序方法:可以创建事件对象的副本或将其转换为字符串。

  • 事件流方法:用于从事件流中删除事件对象(主要是在运行时的 SWF 内容中使用 ActionScript 3.0 时使用,请参阅事件流)。

  • 默认行为方法:可阻止默认行为或检查是否已阻止默认行为。

Event 类实用程序方法

Event 类有两个实用程序方法。clone() 方法用于创建事件对象的副本。toString() 方法用于生成事件对象属性的字符串表示形式以及它们的值。

取消事件默认行为

与取消默认行为有关的两个方法是 preventDefault() 方法和 isDefaultPrevented() 方法。调用 preventDefault() 方法可取消与事件关联的默认行为。使用 isDefaultPrevented() 方法可检查是否已对事件对象调用 preventDefault()

preventDefault() 方法仅在可以取消事件的默认行为时才起作用。您可以通过查阅 API 文档,或通过检查事件对象的 cancelable 属性,来检查事件是否有可以取消的行为。

取消默认行为对事件对象通过事件流的进度没有影响。使用 Event 类的事件流方法可以从事件流中删除事件对象。

Event 类的子类

对于很多事件,Event 类中定义的一组公共属性已经足够了。然而,要表示其他事件,则需要使用 Event 类中未提供的属性。AIR API 为这些事件定义了 Event 类的几个子类。

每个子类提供了对该类别的事件唯一的附加属性和事件类型。例如,与鼠标输入相关的事件提供了描述发生事件时鼠标所在位置的属性。同样,InvokeEvent 类也增加了一些属性,这些属性包含执行调用的文件的文件路径,以及在调用命令行期间作为形参传递的所有实参。

Event 子类频繁定义用来表示与该子类关联的事件类型的其他常量。例如,FileListEvent 类定义表示 directoryListingselectMultiple 事件类型的常量。

使用 JavaScript 处理运行时事件

运行时类支持使用 addEventListener() 方法添加事件处理函数。若要为某个事件添加处理函数,请调用调度该事件的对象的 addEventListener() 方法,同时提供事件类型和处理函数。例如,若要侦听用户单击标题栏上的窗口关闭按钮时调度的 closing 事件,请使用下面的语句:

window.nativeWindow.addEventListener(air.NativeWindow.CLOSING, handleWindowClosing);

addEventListener() 方法的 type 参数为字符串,但 AIR API 为所有运行时事件类型定义了常量。与使用字符串版本相比,使用这些常量可帮助您更快地找到在 type 参数中输入的拼写错误。

创建事件处理函数

下面的代码创建一个简单的 HTML 文件,用于显示有关主窗口位置的信息。一个名为 moveHandler() 的处理函数侦听主窗口的 move 事件(由 NativeWindowBoundsEvent 类定义)。

<html> 
    <script src="AIRAliases.js" /> 
    <script> 
        function init() { 
            writeValues(); 
            window.nativeWindow.addEventListener(air.NativeWindowBoundsEvent.MOVE, 
                                                     moveHandler); 
        } 
        function writeValues() { 
            document.getElementById("xText").value = window.nativeWindow.x; 
            document.getElementById("yText").value = window.nativeWindow.y; 
        } 
        function moveHandler(event) { 
            air.trace(event.type); // move 
            writeValues(); 
        } 
    </script> 
    <body onload="init()" /> 
        <table> 
            <tr> 
                <td>Window X:</td> 
                <td><textarea id="xText"></textarea></td> 
            </tr> 
            <tr> 
                <td>Window Y:</td> 
                <td><textarea id="yText"></textarea></td> 
            </tr> 
        </table> 
    </body> 
</html>

当用户移动此窗口时,textarea 元素会显示此窗口的更新的 X 位置和 Y 位置:

请注意,事件对象作为实参传递给 moveHandler() 方法。利用 event 参数,处理函数可以检查事件对象。在此示例中,使用事件对象的 type 属性报告该事件为 move 事件。

注: 指定 listener 参数时,不要使用括号。例如,在下面对 addEventListener() 方法的调用中,指定 moveHandler() 函数时没有使用括号:addEventListener(Event.MOVE, moveHandler)

addEventListener() 方法包括三个其他参数,在针对 HTML 开发人员的 Adobe AIR API 参考中进行了介绍;这些参数为 useCapturepriorityuseWeakReference

删除事件侦听器

可以使用 removeEventListener() 方法删除不再需要的事件侦听器。建议删除将不再使用的所有侦听器。必需的参数包括 eventNamelistener 参数,这些参数与 addEventListener() 方法的必需参数相同。

删除执行导航的 HTML 页面中的事件侦听器

当 HTML 内容进行导航时,或者因包含 HTML 内容的窗口关闭而丢弃这些 HTML 内容时,不会自动删除引用已卸载的页面中对象的事件侦听器。当对象向已卸载的处理函数调度事件时,会显示下面的错误消息:“应用程序尝试引用不再处于已加载状态的 HTML 页面中的 JavaScript 对象。”(The application attempted to reference a JavaScript object in an HTML page that is no longer loaded.)

为避免出现此错误,请在 HTML 页面退出之前删除其中的 JavaScript 事件侦听器。如果发生页面导航(在 HTMLLoader 对象中),请在 window 对象的 unload 事件发生期间删除事件侦听器。

例如,下面的 JavaScript 代码删除 uncaughtScriptException 事件的事件侦听器:

window.onunload = cleanup; 
window.htmlLoader.addEventListener('uncaughtScriptException', uncaughtScriptException); 
function cleanup() 
{ 
    window.htmlLoader.removeEventListener('uncaughtScriptException', 
                            uncaughtScriptExceptionHandler); 
}

为避免在关闭包含 HTML 内容的窗口时发生错误,请调用 cleanup 函数以响应 NativeWindow 对象 (window.nativeWindow) 的 closing 事件。例如,下面的 JavaScript 代码删除 uncaughtScriptException 事件的事件侦听器:

window.nativeWindow.addEventListener(air.Event.CLOSING, cleanup); 
function cleanup() 
{ 
    window.htmlLoader.removeEventListener('uncaughtScriptException', 
                            uncaughtScriptExceptionHandler); 
}

为了防止发生此错误,您还可以在事件侦听器运行时将其删除(如果该事件只需要处理一次)。例如,下面的 JavaScript 代码通过调用 HTMLLoader 类的 createRootWindow() 方法创建一个 html 窗口,并为 complete 事件添加一个事件侦听器。在调用 complete 事件处理函数时,它会使用 removeEventListener() 函数删除它自己的事件侦听器:

var html = runtime.flash.html.HTMLLoader.createRootWindow(true); 
html.addEventListener('complete', htmlCompleteListener); 
function htmlCompleteListener() 
{ 
    html.removeEventListener(complete, arguments.callee) 
    // handler code.. 
} 
html.load(new runtime.flash.net.URLRequest("second.html"));

如果删除不需要的事件侦听器,则还会使系统垃圾回收器能回收与这些侦听器关联的任何内存空间。

检查有无现有的事件侦听器

hasEventListener() 方法用于检查某个对象是否存在事件侦听器。

没有侦听器的错误事件

异常(而不是事件)是在运行时类中处理错误的主要机制。不过,异常处理对异步操作(例如加载文件)不起作用。如果在异步操作过程中发生错误,则运行时会调度一个错误事件对象。如果您不为该错误事件创建侦听器,则 AIR Debug Launcher 将显示包含有关该错误的信息的对话框。

大多数错误事件都基于 ErrorEvent 类,并且都有一个名为 text 的属性,此属性用于存储描述性错误消息。异常属于 StatusEvent 类,此类具有一个 level 属性,而不是 text 属性。当 level 属性的值为 error 时,StatusEvent 被视为错误事件。

错误事件不会导致应用程序停止运行。它仅以一个对话框的形式显示在 AIR Debug Launcher 中。它根本不会在运行时中运行的已安装 AIR 应用程序中显示。