芒果小站

  1. 全球最具业界良心的主机 - DigitalOcean

    毫无疑问,目前做得最好的主机供应商

    猛击这里查看

  2. 芒果小站目前使用的主机 - DigitalOcean

    客服响应快,随时退款,XEN 架构稳定

    猛击这里查看

  3. 最好的日本东京线路主机 - DigitalOcean

    可选弗里蒙特、达拉斯、亚特兰大、纽瓦克、伦敦、东京机房

    猛击这里查看

  • 1
  • 2
  • 3
切换到精简模式
2

YUI 2: Event Utility

作者 芒果/分类 代码/发布于 2010-02-27 22:42

通过为 DOM 事件的订阅、浏览器事件对象属性的查询提供简单接口,YUI Event Utility 简化了基于浏览器的事件驱动应用程序的创建。Event Utility 包含了自定义事件对象,允许使用自己的代码发布事件,使页面上的其他组件能够订阅并予以响应。Event Utility 包提供了下列功能:

1. 将事件处理程序附加到一个或多个元素
2. 自动延缓暂不可用元素的事件注册
3. 自动纠正作用域,可选作用域赋值
4. 浏览器事件对象的自动抽象
5. 将任意对象发送到某一个事件
6. Utility 方法访问需要浏览器抽象的事件属性
7. 自动清除事件监听
8. 自定义事件的创建和订阅机制
9. 在检测到 DOM 元素时即刻执行函数

入门

使用 Event 和 Custom Event Utilities (自定义事件工具包) 需要在页面中包含以下源文件:

<!-- Dependency -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/yahoo/yahoo-min.js" ></script>

<!-- Event source file -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js" ></script>

Event 和 Custom Event components (自定义事件组件) 分别由 YAHOO.util.Event 和 YAHOO.util.CustomEvent 定义。

基本事件

为 DOM 添加事件处理程序,需要简单定义,并同时指定需绑定元素和事件类型等参数,将其传递给 Event Utility:

var oElement = document.getElementById("elementid");
function fnCallback(e) { alert("click"); }
YAHOO.util.Event.addListener(oElement, "click", fnCallback);

代码注释:

1. 声明变量 oElement 并将其赋值为特定的 DOM 元素。
2. 定义回调函数,fnCallback(e),以处理特定事件。
3. 调用 YAHOO.util.Event 对象的 addListener 方法为 DOM 元素绑定事件。addListener 方法需要三个参数:要绑定事件的元素 (oElement),要绑定的事件,以及回调函数。

通过元素 ID 添加事件处理程序,使用以下代码:

function fnCallback(e) { alert("click"); }
YAHOO.util.Event.addListener("elementid", "click", fnCallback);

这个例子与第一个类似。但是,此处我们通过 HTML ID (“elementid” 作为一个字符串) 来查找元素,而不是通过传递一个指向元素对象的变量。Event Utility 尝试通过 ID 属性值找到 DOM 元素,如果不能立即找到,则在页面就绪后继续查找元素,最多长达 15 秒。这种“自动延缓”机制使你在许多情况下,可以直接将事件代码写入脚本,而不是从那些只能在页面就绪后才能执行的函数中分离出来。

为多个元素添加事件处理程序,使用以下代码:

// array can contain object references, element ids, or both
var ids = ["el1", "el2", "el3"];
function fnCallback(e) { alert(this.id); }
YAHOO.util.Event.addListener(ids, "click", fnCallback);

代码注释:

1. 为页面元素的 HTML ID 属性声明一个数组。该数组以字符串的形式存储 HTML ID (如代码所示),也可以接受对象引用变量。
2. 声明回调函数,fnCallback(e),用于处理特定事件。
3. 调用 YAHOO.util.Event 的 addListener 方法,为 DOM 元素绑定事件。此处 addListener 方法的第一个参数是 ID 数组,而不是一个单独的元素或 ID。

阅读更多细节请查阅 使用事件使用自定义事件 中的示例,或者参考 API 文档。也可以查阅关于如何使用 addListener 添加事件的 第一个 Event Utility 示例 教程。

注:开发人员经常不知道在哪里可以找到 DOM 事件的完全列表(例如 “click”、”mousemove” 等等),但至今仍然没有完美的手册,Danny Goodman 的 DHTML: The Definitive Reference 可能比较全面。PPK 关于怪异模式的 Event Compatibility Table 可能是线上最好的兼容性评估。Event Utility 对事件处理程序的绑定没有任何限制;它将尝试为你提供的任何事件名称添加监听。你有责任确保所使用的事件得到当前浏览器开发环境的支持。

使用事件

这部分描述了 Event Utility 的一些常用功能和使用方法。包括以下部分:

Handler Attachment Deferral
Automatic Scope Correction
Automatic Event Object Browser Abstraction
Send an Arbitrary Object to the Event Handler

延缓附加处理程序

如果你尝试在页面完全就绪前为元素添加处理程序,Event Utility 会尝试定位元素。如果元素不可用,事件会定期检测,直到 window.onload 事件被触发。处理程序延缓只能在通过元素 ID 添加处理程序时生效;如果您尝试添加的对 DOM 对象的引用尚不可用,该组件无法获取你试图访问的对象。

自动作用域纠正

附带 Internet Explorer 的 attachEvent 方法的事件处理程序在 window 作用域内被执行,因此回调函数中的特殊变量 this 引用了 window 对象,这并不是非常有用。更令人烦恼的是,实际上 Internet Explorer 中的事件对象不提供查找已注册事件的元素的可靠方法;基于标准的浏览器通过 currentTarget 属性对此给予了良好支持,但 IE 不存在这个属性。

默认情况下,Event Utility 自动调整执行环境的作用域,因此 this 关键字会遵循 W3C-兼容浏览器中的 addEventListener 行为,查找绑定事件的 DOM 元素。此外,事件订阅者可以覆盖作用域,因此 this 关键字会查询传入 addListener 的自定义对象。

浏览器事件对象的自动抽象

当事件触发后回调函数接收的第一个参数总是实际事件对象。没有必要在 window.event 中查看。

发送任意对象到事件处理程序

在面向对象的 JavaScript 开发中,通常通过指定自定义对象的成员方法来监听事件,在响应时访问内部属性和执行内部方法。由于事件处理程序 (默认情况下) 在元素作用域内执行,而不是监听方法的父级对象的作用域,自定义对象的属性不能通过 “this” 关键字获得。你可以通过以下方法解决这个问题:(1) 创建闭包 (2) 创建自定义对象和元素之间的循环引用。

Event Utility 使你能够直接将自定义对象传递给事件处理程序,因此不必使用其他方法 (有潜在漏洞的) 访问该自定义对象。将自定义对象作为第四个参数传给 addListener 方法,作为第二个参数传给回调函数 (第一个参数是事件对象本身):

function MyObj(elementId, customProp, callback) {
   this.elementId = elementId;
   this.customProp = customProp;
   this.callback = callback;
}

MyObj.prototype.addClickHandler = function() {
   YAHOO.util.Event.addListener(this.elementId, "click", this.callback, this);
};

function fnCallback1(e, obj) {
  // the execution context is the html element ("myelementid")
  alert(this.id + " click event: " + obj.customProp);
}

function fnCallback2(e, obj) {
  // the execution context is the custom object
  alert("click event: " + this.customProp);
}

var myobj = new MyObj("myelementid", "hello world", fnCallback1);
var mydata = { id: 10 };

// One way to add the handler:
myobj.addClickHandler();

// This will do the same thing:
YAHOO.util.Event.addListener("myelementid", "click", fnCallback1, myobj);

// If we pass true as the final parameter, the custom object that is passed
// is used for the execution scope (so it becomes "this" in the callback).
YAHOO.util.Event.addListener("myelementid", "click", fnCallback2, myobj, true);

// Alternatively, we can assign a completely different object to be the
// execution scope:
YAHOO.util.Event.addListener("myelementid", "click", fnCallback2, mydata, myobj);

移除事件

你可以通过调用 YAHOO.util.Event.removeListener 并使用与创建事件时同样的事件签名来移除事件监听。

YAHOO.util.Event.removeListener("myelementid", "click", fnCallback1);

如果不方便保存原先用于注册事件的回调函数的引用参数,而且事件具有唯一监听者,你可以调用不带参数的 removeListener 函数。这样做将删除所有通过 addListener 为指定元素和事件类型添加的监听。

YAHOO.util.Event.removeListener("myelementid", "click");

YAHOO.util.Event.getListeners 允许你检索所有通过 addListener 方法绑定的元素监听。或者,你可以检索指定类型的监听:

// all listeners
var listeners = YAHOO.util.Event.getListeners(myelement);
for (var i=0; i>listeners.length; ++i) {
    var listener = listeners[i];
    alert( listener.type   ); // The event type
    alert( listener.fn     ); // The function to execute
    alert( listener.obj    ); // The custom object passed into addListener
    alert( listener.adjust ); // Scope correction requested, if true, listener.obj
                              // is the scope, if an object, that object is the scope
}

// only click listeners
var listeners = YAHOO.util.Event.getListeners(myelement, "click");

YAHOO.util.Event.purgeElement 允许你移除所有通过 addListener 方法注册的元素监听。或者,可以指定特定类型的监听,此外,该元素的子节点也会被清除。

// all listeners
YAHOO.util.Event.purgeElement(myelement);
// all listeners and recurse children
YAHOO.util.Event.purgeElement(myelement, true);
// only click listeners
YAHOO.util.Event.purgeElement(myelement, false, "click");

使用 focusin 和focusout 事件

由于 DOM 中的 focus 和 blur 事件不支持冒泡,可以使用 Event Utility 的 focusin 和 focusout 事件替代 DOM 中可聚焦元素的 focus 和 blur 事件处理程序。focusin 和 focusout 事件使监听单一元素、监听元素所有子节点触发的 focus 和 blur 事件成为了可能。由于减少事件监听数目是一个行之有效的性能提高策略,使用 focusin 和 focusout 事件有助于加速任何需要监听可聚焦元素的网页或应用程序。

创建 focusin 监听

考虑以下 HTML 代码:

<div id="toolbar">
    <input type="button" id="button-cut" name="button-cut" value="Cut">
    <input type="button" id="button-copy" name="button-copy" value="Copy">
    <input type="button" id="button-paste" name="button-paste" value="Paste">
</div>

监听每个 toolbar 容器中每个按钮的 focus 事件时,通常需要对每个按钮添加离散的监听事件。然而,使用 Event Utility 则可以单独监听容器元素 (此处是 <div id=”toolbar”>),并在每个按钮获得焦点时予以通知。

YAHOO.util.Event.on("toolbar", "focusin", function(e) {

    YAHOO.log("target: " + e.target.id);

});

使用 mouseenter 和 mouseleave 事件

受 Internet Explorer 的 mouseenter 和 mouseleave 事件影响,Event Utility 提供了在所有 A 级浏览器中监听 mouseenter 和 mouseleave 事件的功能。为应对在鼠标悬停和移开时执行 DOM 操作,使用 mouseenter 和 mouseleave 可以提高性能,因为他们不会冒泡,DOM 的变化将不会过于频繁。

mouseenter 和 mouseleave 功能被封装在一个单独的 Event Utility 增强模块中,因此监听 mouseenter 和 mouseleave 事件必须在包含 Event Utility 之后引入 event-mouseenter 模块。

<!-- Dependency -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/yahoo/yahoo-min.js" ></script>

<!-- Event source file -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js" ></script>

<!-- Dom source file -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/dom/dom-min.js" ></script>

<!-- MouseEnter source file -->
<script src="http://yui.yahooapis.com/2.8.0r4/build/event-mouseenter/event-mouseenter-min.js" ></script>

创建 mouseenter 和 mouseleave 监听

考虑以下 HTML 代码:

<div id="container">
    <ul>
        <li><em>Item Type One</em></li>
        <li><em>Item Type Two</em></li>
        <li><em>Item Type Three</em></li>
    </ul>
</div>

以下代码将为列表容器 (<div id=”container”>) 添加 mouseenter 和 mouseleave 监听。mouseenter 监听会在鼠标进入容器时被调用一次。mouseleave 监听会在鼠标离开容器时被调用一次。

YAHOO.util.Event.on("container", "mouseenter", function (e) {

    YAHOO.log("Mouse entered: " + this.id);

});

YAHOO.util.Event.on("container", "mouseleave", function (e) {

    YAHOO.log("Mouse left: " + this.id);

});

使用委托方法

事件委托 (Event delegation) 支持在父级元素上应用单独的事件处理程序,来监听影响后代元素的交互行为。因为后代元素的事件将冒泡到父级元素,对于减少特定网页上事件处理程序的资源消耗问题,这可能是一个可靠的、非常有效的缓解策略。(你可以在这篇 YUIBlog 文章中阅读更多有关事件委托的内容)

创建委托事件监听

考虑以下 HTML 代码:

<div id="container">
    <ul>
        <li id="item-1"><em>Item Type One</em></li>
        <li id="item-2"><em>Item Type Two</em></li>
        <li id="item-3"><em>Item Type Three</em></li>
    </ul>
</div>

使用 delegate 方法,需要将委托容器的元素 id 作为第一个参数 (此处是 <div id=”container”>) 传入。第二个参数是需要委托的事件类型,第三个参数是事件监听函数,第四个参数是定义后代元素 (监听被调用时必须按照顺序匹配事件目标) 的 CSS 选择器。

以下示例将为容器 (<div id=”container”>) 绑定一个单独的 click 事件监听。但这个监听只有在事件目标为 <li> 时被调用。

YAHOO.util.Event.delegate("container", "click", function(e, matchedEl, container) {

    //  The list item that matched the provided selector is the default scope
    YAHOO.log("Default scope: " + this.id);

    //  The list item that matched the provided selector is also passed
    //  as the second argument in case the scope of the listener
    //  is adjusted
    YAHOO.log("Clicked list item: " + matchedEl.id);

    //  The actual click target, which could be the matched item or a
    //  descendant of it.
    YAHOO.log("Event target: " + YAHOO.util.Event.getTarget(e));    

    //  The delegation container is passed as a third argument
    YAHOO.log("Delegation container: " + container.id);

}, "li");

使用 onAvailable 和 onContentReady 方法

onAvailable 允许你定义一个函数,一旦元素在 DOM 中被检测到,该函数即刻执行。其目的是减少在渲染行内脚本和 HTML 代码时发生时序问题。这并不意味着用来为文档就绪后的最终元素定义处理程序;而是用来在加载过程中检测元素。

onAvailable 的参数签名和 addListener 相似,只省略事件类型。

 function TestObj(id) {
   YAHOO.util.Event.onAvailable(id, this.handleOnAvailable, this);
 }

 TestObj.prototype.handleOnAvailable = function(me) {
   alert(this.id + " is available");
 }

 var obj = new TestObj("myelementid");
<div id="myelementid">my element</div>

onContentReady 方法使用和 onAvailable 相同的语法。两者之间的实质差异在于,onContentReady 等待直到 DOM 中的目标元素和其直接后继元素响应 getElementById。这保证了目标元素的内容被完全载入 (除了可以通过脚本添加的任何动态内容)。如果 onContentReady 一直检测不到直接后继元素,它将随 window.load 事件触发。

使用 onDOMReady 方法

onDOMReady 允许你定义一个函数,一旦 DOM 呈可用状态,该函数即刻执行。DOM 在结构完整之前不会被视为可用;如果脚本试图在未就绪的 DOM 中插入信息,一些浏览器本身的 bug (主要在 IE 中) 会导致浏览器崩溃或者页面载入失败。DOM 会在图片完成载入之前就绪,然而,这样的 onDOMReady 通常是使用 window 对象的 load 事件的一个优良选择。

 function init() {
    YAHOO.util.Dom.setStyle("hidden_element", "visibility", "");
 }
 YAHOO.util.Event.onDOMReady(init);

 // As with addListener, onAvailable, and onContentReady, you can pass a data object and adjust the scope
 // YAHOO.util.Event.onDOMReady(init, data, scope);

使用 CustomEvent 对象

CustomEvent 对象使你能够定义和使用 DOM 中默认不可用的事件 – 即应用程序中自定义的特定事件。这部分描述了几个 CustomEvent 组件的通用方法并提供一些示例。包括以下内容:

Defining a Custom Event
Subscribing (Listening) to a Custom Event
Creating a Callback
Triggering the Event

定义一个自定义事件

定义一个自定义事件类型,需要创建一个 CustomEvent 对象实例:

// custom object
function TestObj(name) {
    this.name = name;
    // define a custom event
    this.event1 = new YAHOO.util.CustomEvent("event1", this);
}

CustomEvent 构造器创建了一个全新的自定义事件;它需要一个必要参数和三个可选参数:

type – 事件类型。这个字符串会返回到接收这个事件的监听,以此获知事件的发生。
scope – 监听方法触发时所在的作用域;如果没有指定作用域,默认为 window 对象。
silent – 默认为 false。如果为 true,在调试模式下该事件的活动将不被记录。
signature – 指定事件监听的签名。选项为:

YAHOO.util.CustomEvent.LIST (默认):
参数一:事件名称
参数二:发送到触发事件的参数数组
参数三:(可选) 一个由订阅者提供的自定义对象
YAHOO.util.CustomEvent.FLAT:
参数一:传递到触发事件的第一个参数。如果你需要传递多个参数,使用数组或者对象字面量。
参数二:一个由订阅者提供的自定义对象

事件订阅者可以覆盖作用域,因此 this 关键字指向传递到 subscribe 方法的自定义对象。

订阅 (监听) 自定义事件

订阅一个自定义事件,需要使用 subscribe 方法:

// a custom consumer object that will listen to "event1"
function Consumer(name, testObj) {
    this.name = name;
    this.testObj = testObj;
    this.testObj.event1.subscribe(this.onEvent1, this);
}

在这个示例中,event1 是在上一小节创建的自定义事件对象。使用 subscribe 方法监听该事件。subscribe 方法需要两个参数。第一个是回调函数;第二个是自定义对象 (详细参考 Send an Arbitrary Object to the Event Handler)。当事件被触发时,回调函数被调用,并且自定义对象作为第三个参数被传递到该回调函数 (当使用默认参数签名;当使用单位签名时,自定义对象作为第二个参数)。

创建回调函数

为自定义事件创建回调函数:

Consumer.prototype.onEvent1 = function(type, args, me) {
    alert(" this: " + this +
        "\n this.name: " + this.name +
        "\n type: " + type +
        "\n args[0].data: " + args[0].data +
        "\n me.name: " + me.name);
}

该示例中 type 参数是事件类型 (此处为 “event1”),args 是所有传入自定义事件触发方法的参数数组,并且 me 是我们创建订阅事件时传入的自定义对象。

触发事件

触发一个自定义事件:

// random test data to be used as an event argument
function TestData(data) {
    this.data = data;
}

// create an instance of our test object
var t1 = new TestObj("mytestobj1");

// create the event consumer, passing in the custom
// object so that it can subscribe to the custom event
var c1 = new Consumer("mytestconsumer1", t1);

// create a data object that will be passed to the consumer when the event fires
var d1 = new TestData("mydata1");

// fire the test object's event1 event, passing the data object as a parameter
t1.event1.fire(d1);

该示例中 t1 是我们创建的测试对象,event1 是 CustomEvent 示例,d1 是测试数据。这个示例产生以下输出:

 this: [object Object]
 this.name: mytestobj1
 type: event1
 args[0].data: mydata1
 me.name: mytestconsumer1

英文原稿:YUI 2: Event Utility | Yahoo! Developer Network
翻译整理:YUI 2: Event Utility | 芒果

版权所有,转载请注明出处。
转载自 <a href="http://mangguo.org/yui-2-event-utility/" title="YUI 2: Event Utility" rel="bookmark">YUI 2: Event Utility | 芒果小站</a>
如果喜欢这篇文章,欢迎订阅芒果小站以获得最新内容。

已经有 2 条群众意见

  1. 明河共影 /2010-09-17 19:21

    这么好的文章,居然没人顶,呵呵,明河坐个沙发。 回应

    #1
  2. ?
    YUI 2: Event Utility | zend实验室-java/php学习教程、web前端设计、网站建设、网页设计、网络SEO推广 /2011-05-03 22:58

    […] 转载至:YUI 2: Event Utility | 芒果小站 分类: css, 其它 标签: 临时 5 个简单实用的 CSS 属性纯 CSS 实现文本渐变效果CSS 的外联,内联和嵌入芒果教你清除浮动CSS 有序列表 ol 和无序列表 ul用 JavaScript 实现 HTML 代码运行框你真的认识 window.location 吗?使用 <hr> 标签创建水平分隔线用 CSS 实现段落首行缩进多层元素嵌套的圆角按钮 评论 (0) Trackbacks (0) 发表评论 Trackback […] 回应

    #2

下面我简单说几句