- 浏览: 49484 次
- 性别:
- 来自: 北京
最新评论
-
hanxiao84322:
强大啊,虽然没有完全看明白。
YUI 3.0应用初探 -
osacar:
不行啊。没效果!在Opera下测试
IE也不行。
JS iframe跨域自适应内容高度 -
xxzjzb1:
中秋送礼,首选书画、艺术品交易平台爱艺购!
JS将数字转换成三位逗号分隔的样式 -
mozart0:
货币:num.toFixed(2).replace(/(\d) ...
JS将数字转换成三位逗号分隔的样式 -
cnxxg:
这样能处理一个元素含有多个classname的情况吗?
javascript 整合的获取ID,className,tagName的方法
YUI3:事件
YUI的事件功能为响应DOM事件提供一个简单的接口,让在浏览器中创建事件驱动的应用更容易了。YUI的事件功能包包含自定义事件对象(Custom Event object),自定义事件让你可以在代码中发布(publish)某一个瞬间或某一个事件,以便页面上其他的组件能订阅(subscribe)这些事件然后响应这些事件。
YUI的事件功能包有以下功能:
DOM事件处理
自动延迟解析(deferral)赋给不可用元素的处理器
自动调整函数执行环境(scope),可选择地指定函数执行环境
将浏览器差异规范化的event facade
自动清除DOM事件监听
易用的事件代理处理
在所有A级浏览器中的事件模拟
页面加载事件(元素层级的available和contentready以及DOM层级的domready)
键盘监听功能,响应特定的组合键
获得焦点/失去焦点事件抽象层,提供代理监听这些事件的能力
冒泡(bubbleable)、可取消(cancelable)的自定义事件,有内在的AOP特性
实现可定义的DOM事件,用以描述原生事件不提供的DOM的状态
Luke Smith – 事件进化
Luke Smith对YUI3的事件系统做深入的介绍,内容包括对DOM事件、事件代理、事件模拟、自定义事件的支持。
开始
引入相关文件
为YUI的事件功能引入源文件及相关文件最简单的办法是使用如下标签将YUI种子文件添加到你的页面中。YUI实例会自己加载所需文件。
<script type="text/javascript" charset="utf-8"
src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js">
</script>
当使用’event’模块时,YUI实例会自动加载YUI的事件功能的源文件以及相关文件。让YUI实例自动加载相关文件,可以避免手工管理页面组件所需的文件列表,还可以优化初始页面大小。
如果你想手工引入所需文件,可以使用YUI Dependency Configurator工具得到所需文件列表。
YUI实例
一旦页面上有YUI种子(yui-min.js)文件后,你可以创建一个新的YUI实例,通过use方法的第一个参数指定要加载的模块。
// Create new YUI instance, and populate it with the required modules
YUI().use('event', function(Y) {
// Event available, and ready for use.
});
传给use方法的最后一个参数是一个回调函数。当YUI实例加载完页面所需的文件后,该回调函数会被调用。一旦加载完那些文件后,实现’event’模块以及它依赖的模块的类会被提供给YUI实例。被赋予功能的YUI实例的引用会通过回调函数的参数传入回调函数中。然后,你就可以在你的回调函数中,基于你配置的YUI实例编写你的应用了。
关于YUI实例的创建和use方法的更多内容,请看YUI全局对象。
DOM事件
为DOM添加事件处理器很简单。定义事件处理器(函数),把事件处理器、事件名称引用、处理器绑定到的元素这三项传递给YUI的事件功能(Event Utility):
//处理该事件的函数
function handleClick(e) {
//将event facade传给log函数输出:
Y.log(e);
}
//假设我们在页面上有一个ID为"foo"的元素:
YUI().use('node-base', function(Y) {
Y.on("click", handleClick, "#foo");
});
代码解读:
1:创建一个YUI实例——YUI的事件功能依赖于’node-base’模块,所以YUI().use(“node-base”)会加载YUI的事件功能核心特性所需的文件。如果你加载’event-base’模块,也会得到一样的功能。一些特殊的事件实现被包装成子模块,不包含在’event-base’中。这些特殊的模块在下面会讲到,可以通过它们的名字加载他们。或者直接加载’event’模块,它包含所有的DOMYUI的事件功能。
2:定义一个回调函数来处理指定事件:handleClick(e)。
3:调用YUI实例的on方法,将事件绑定到DOM元素上。on方法要求三个参数:要绑定的事件(“click” 字符串),回调函数(handleClick),还有事件绑定到的元素(“#foo”,假定元素的ID为’foo’)。
因为我们通过ID来指定元素(‘#foo’ 字符串),而不是传入Node的引用或者是HTMLElement的引用,所以可以指向一个还未存在于页面上的元素。YUI的事件功能(Event Utility)通过ID查找元素,如果找不到,在页面加载完成15秒后,会再尝试地找一次。这个“自动异步”的功能让你在某些情况下直接在你的脚本中直接编写事件处理添加代码(event attachment code),而不是需要把这些事件处理添加代码写到一个页面加载完成才执行的函数中。
使用CSS选择器语法,以数组的形式传入多个选择字符串(selector string)、以数组的形式传入Node实例、以数组的形式传入DOM元素,为多个元素添加事件处理器。
YUI().use('node-base', function(Y) {
//可以通过选择器语法选择目标元素
Y.on("click", handleClick, "#foo p"); //把#foo元素下的所有的p节点作为目标
//elements can be targeted by Node references:
var foo = Y.one("#foo");
Y.on("click", handleClick, foo);
foo.on("click", handleClick); //同上
//可以传入元素的直接引用
var foo = document.getElementById("foo");
Y.on("click", handleClick, foo);
//在所有情况下,你可以传入一个数组
Y.on("click", handleClick, ["#foo p", "#bar"]);
});
使用on方法:控制执行环境和参数
使用Y.on,需要以下参数:
1. 事件名:指向响应的DOM事件的字符串(如:“click”或“mouseover”)。开发人员经常希望能有一个所有浏览器都支持的DOM事件完整列表。但是这样的列表不存在。Danny Goodman的DHTML: The Definitive Reference 中有最完整的信息。quirksmode网站上PPK的Event Compatibility Table有最好的兼容性评价。YUI的事件功能不对你要附加处理器(监听)的事件做任何的限制,它会尝试地监听你提供的任何事件。所以,确保你针对开发的浏览器能兼容你提供的事件就是你的责任了。
2. 处理器(handler):当事件发生时调用的函数的引用。
3. 元素:如前面所说,这可以是一个或多个选择器语法的引用、Node实例、DOM元素的引用。
4. 执行环境对象:对为事件处理函数提供执行环境的对象的引用——也就是函数中this的指向。如果省略该参数,执行环境对象就是事件目标元素的Node实例。
以下是这些参数的应用实例代码:
<div id="list">
<ul>
<li id="one" class="odd">Item one</li>
<li id="two" class="even">Item two</li>
<li id="three" class="odd">Item three</li>
<li id="four" class="even">Item four</li>
</ul>
</div>
//配置YUI实例
YUI().use("dump", "node-base", function(Y) {
//随便创建一个执行环境对象
var contextObj = {
name: "context"
};
//处理点击事件的函数,输出报告信息
function handleClick(e, arg1, arg2) {
Y.log("Context object:" + Y.dump(this));
Y.log("Event facade object:" + Y.dump(e));
Y.log(arguments);
}
//让单数列表项订阅点击事件
Y.on("click", handleClick, "#list .odd", contextObj, "argumentOne", "argumentTwo");
});
运行这些代码,点击列表的第一个和第三个,Y.log会输出以下信息:
Context object: {name => context}
Event facade object: {
altKey => false,
cancelBubble => false,
ctrlKey => false,
//and remaining event facade properties
...}
最后输出的arguments对象,会包含以下三个项目:
e(event facade)、”argumentOne”(字符串)、“argumentTwo”(字符串)
以前版本的方法:Event.addListener和Event.on
YUI的事件功能包含两个添加事件监听器的两个老的方法:这两个方法包含在Event包中,遵循YUI以前版本YUI的事件功能的语法。如果你使用YUI3.x,应该避免使用这些老的方法,而是使用上面的方法。
移除事件
移除事件监听器有3种方式:
1. 为事件名参数添加事件分类前缀,在移除事件监听器时将这个字符串传给YUI的detach方法。
2. 在事件处理器对象上调用detach方法:on方法的返回值是一个事件处理器对象,该对象有一个detach方法,可以用以移除对应的事件监听器。
3. 调用YUI的detach方法,传入事件名、处理函数、元素三个参数:detach是YUI实例的方法,当你访问不到事件处理器对象时,可以使用该方法。
示例代码:
//配置YUI实例
YUI().use('node-base', function(Y) {
//定义一个事件处理函数
function handleClick(e) {
Y.log(e);
}
// 为foo元素添加事件处理器。事件名中的‘eventcategory|’部分可在移除监听器时用以识别移除哪一个事件的监听器。
var fooHandle = Y.on("eventcatgory|click", handleClick, "#foo");
// 通过事件名的前缀移除事件监听器
Y.detach('eventcategory|click');
// 通过事件处理器对象移除事件监听器
fooHandle.detach();
// 移除‘eventcategory’分类下所有的事件监听器
Y.detach('eventcategory|*');
// 通过detach方法移除
Y.detach("click", handleClick, "#foo");
// 为detach传入事件处理对象也可以移除
Y.detach(fooHandle);
});
模拟事件
模拟出来的事件是浏览器创建的事件。大部分情况下,他们的行为和用户触发的事件是一样的。模拟的事件会冒泡,事件对象有包含关于该事件数据的属性。有时候这些属性是某些浏览器专有的,所以,建议你使用Y.Event的跨浏览器方法来获取这些属性正确的值,比如target、relatedTarget、和charCode。在事件发生的过程中,事件处理器都同步地在事件目标上被调用。我们使用Y.Node实例的simulate方法来模拟事件。
鼠标事件
以下是可以模拟的7个鼠标事件:
click
dbclick
mousedown
mouseup
mouseover
mouseout
mousemove
每一个事件都是在调用simulate方法是被触发,触发时会传入两个参数:触发的事件名和指定事件额外信息的可选的对象。比如,要模拟页面body元素的点击事件,代码如下:
//配置YUI实例
YUI().use('node-event-simulate', function(Y) {
Y.one("body").simulate("click");
});
以上的代码模拟body上的click事件,事件对象上包含所有默认的属性。要给事件指定额外的信息(比如Shift键按下),必须使用第二个参数并为事件属性指定准确的DOM名(在必要时,跨浏览器逻辑会处理跨浏览器的问题)。
YUI().use('node-event-simulate', function(Y) {
Y.one("body").simulate("click", { shiftKey: true });
});
在上面更新后的代码中,一个按下Shift键并点击body元素的事件被模拟了。
根据模拟的事件的不同,需要提供的额外的属性也不同,但仅限于以下列表:
detail – 指定一个按钮被点击的次数(仅限于DOM-compliant浏览器)
screenX/screenY – 相对于屏幕,鼠标事件发生的坐标(仅限于DOM-compliant浏览器)
clientX/clientY – 相对于客户端区域,鼠标事件发生的坐标(仅限于DOM-compliant浏览器)
ctrlKey/altKey/shiftKey/metaKey – Ctrl, Alt, Shift, Meta键的状态,true为按下,false为弹起
button – 触发事件的鼠标按钮,0是左键,1是右键,2是中键
relatedTarget – 鼠标从哪个元素移动到目标元素(在mouseover和mouseout事件中)
使用不同的方法和额外属性的实例:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//模拟按下Alt 键并点击
node.simulate("click", { altKey: true});
//模拟按下Ctrl 键双击
node.simulate("dblclick", { ctrlKey: true });
//模拟鼠标经过
node.simulate("mouseover", { relatedTarget: document.body });
//模拟鼠标离开
node.simulate("mouseout", { relatedTarget: document.body });
//模拟在客户端的 (100,100) 点上按下鼠标
node.simulate("mousedown", { clientX: 100, clientY: 100 });
//模拟在客户端的 (100,100) 点上弹起鼠标
node.simulate("mouseup", { clientX: 100, clientY: 100 });
//模拟在客户端的 (200,200) 点上鼠标经过
node.simulate("mousemove", { clientX: 200, clientY: 200 });
});
键盘事件
以下是可以被模拟的键盘事件:
keyup
keydown
keypress
和鼠标一样,键盘事件也是用simulate方法来模拟。对于keyup和keydown事件,必须指定keycode属性。对于keypress事件,必须指定charCode属性。许多情况下,keyCode和charCode会用相同的值来代表相同的按键。(比如,97代表”A”键,也是字母“a”的ASCII码)。
例子:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//模拟按下A键
node.simulate("keydown", { keyCode: 97 });
//模拟弹起A键
node.simulate("keyup", { keyCode: 97 });
//模拟用键盘上打出 "a"
node.simulate("keypress", { charCode: 97 });
});
键盘事件还支持ctrlKey, altKey, shiftKey,metaKey事件属性。
注意:因为浏览器实现不同,键盘事件在不同浏览器中的实现方式也是不同的。比如,当在一个输入框中模拟按键按下事件,只有火狐会用按键代表的字符更新输入框。而在其他的浏览器中,事件也注册了,事件处理函数也被调用了,但是输入框中的字符和value属性都没有更新。将来这些浏览器改进对键盘事件模拟的支持后,这些问题会消失的。
UI事件
以下是可以被模拟的UI事件:
blur
change
focus
resize
scroll
select
和其他一样,UI事件也是使用simulate方法模拟的。因为UI事件没有额外的属性,所以模拟UI事件不需要给事件指定额外的信息。以下是一些实例:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myInput");
//simulate a change event
node.simulate("change");
//simulate a select event
node.simulate("select");
});
使用available事件和contentready事件(原来的onAvailable方法和onContentReady方法)
available让你可以定义一个函数,一旦DOM中检测到某元素时该函数就执行。这样的目的是为了减少渲染script和HTML时的时间先后问题。该事件不是为了用来给有可能存在于页面中的元素添加事件处理器的,而是为了用来在加载过程中检测元素是否可用。
该事件的用法如下:
YUI().use('node-base', function(Y) {
function TestObj(id) {
Y.on('available', this.handleOnAvailable, id, this);
}
TestObj.prototype.handleOnAvailable = function(me) {
Y.log(this.id + " is available");
}
var obj = new TestObj("myelementid");
});
<div id="myelementid">my element</div>
使用contentready事件的语法和使用available事件的语法一样,这两个事件不同的地方在于contentready会等到目标元素和它的下一个兄弟元素能响应getElementById后才触发该事件。这保证了目标元素的内容(后来通过脚本加载的内容除外)的完全加载。如果contentready检测不到目标元素的下一个兄弟元素,它将触发window.load事件。
使用domready事件(原来的onDOMReady)
domready自定义事件让你定义一个函数,该函数在页面的DOM达到一个可用的状态执行。DOM在结构完整时,才会达到可用的状态;有几个bugs,首先在IE下,如果在DOM达到结构完整时的可用状态之前,尝试通过脚本往DOM中插-入内容的话,会引起浏览器崩毁或者是页面不能成功加载。
DOM在图片加载完成之前,也可达到可用状态。所以,domready事件是window对象的load事件的一个完美替代。
YUI().use('node-base', function(Y) {
function init() {
Y.one("#hidden_element").set("visibility", "");
}
Y.on("domready", init);
// 对于所有的自定义事件,你都可以传入执行环境对象和参数,执行对象和参数最终会被传递给处理函数;
// Y.on("domready", init, contexObject, argumentOne, argumentTwo, argumentN);
});
使用key事件
key事件让你定义一个函数,该函数在某键(或组合键)被按下时执行(不管是不是有功能键【modifier】)。
创建一个按键监听器
下面的代码会为一个id为’text1′的元素添加一个按键按下事件监听器。只有返回键值(keyCode 13)被监测到时,监听函数才会执行。当检测到这个事件后,移除该监听器。
YUI().use('event-key', function(Y) {
// 保存Y.on方法的返回值,为了稍后移除监听器
var handle = Y.on('key', function(e, arg1, arg2, etc) {
Y.log(e.type + ": " + e.keyCode + ' -- ' + arg1);
// 阻止事件冒泡和阻止事件stopPropagation() and preventDefault()
e.halt();
// 删除订阅,所以该事件只发生一次
handle.detach();
// 事件监听器添加到元素'text1',指定按下事件,指定keycode为13,指定Y为执行环境对象,添加参数
}, '#text1', 'down:13', Y, "arg1", "arg2", "etc");
});
定义按键监听器的细节
在前面的例子中,’down:13′定义了按键事件监听的细节。这指定了只有返回键触发了按键按下事件,监听器才执行。指定的字符串包含三部分:
1:事件名后跟着一个冒号(‘up:’, ‘down:, or ‘press:’)
2:0个或多个被监听的keyCode,由逗号分隔。如果定义多于一个keyCode,则任意个一keyCode被监测倒都会使监听器开始执行。
3:0个或多个被监听的keyCode,由加号分隔。如果定义了功能键(modifier key),所有的键都被监测到才会使监听器开始执行。
所以,’press:65,66+shift+ctrl’这样的定义,在一个按键按下,shift和control键被按下,并且检测到keyCOde65或66时,才会触发监听器开始执行。
使用delegate方法
事件代理是指在容器元素上添加事件处理器,用以监听后代元素的交互动作。因为子元素的事件会冒泡传播到容器元素,所以这是减少事件处理器数量的稳定有效的策略(关于事件监听的更多内容请看这篇YUI博客上的文章)。
YUI的事件功能提供了一个delegate方法,可以使用CSS选择器语法来定义代理容器元素中首监听器监听的元素,这使事件代理的应用更简单了。
创建一个代理的事件监听器
考虑以下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>
使用Y.delegate方法,将要代理的事件名作为第一个参数,跟着就是监听函数,作为代理父元素的节点(监听器添加到的元素节点),最后是子元素节点,只有事件的目标元素与这些子节点匹配的时候,监听函数才会被调用。
下面的例子是绑定一个点击事件监听器到容器节点(<div id="container">),但只有事件目标是<li>的时候,监听函数才会别调用。
YUI().use("event-delegate", function(Y) {
Y.delegate("click", function(e) {
// 默认情况下,this对象指向匹配的li元素
Y.log("Default scope: " + this.get("id"));
// 如果this对象在订阅的过程中被覆盖了,该li元素也可以通过event的currentTarget属性访问到
Y.log("Clicked list item: " + e.currentTarget.get("id"));
// 真正的点击目标,可能是匹配的li或者它的子元素
Y.log("Event target: " + e.target);
// 代理父元素被添加到event facade对象中。
Y.log("Delegation container: " + e.container.get("id"));
}, "#container", "li");
});
Nodes上也有delegate方法,所以以下是另一种语法:
YUI().use("node", function(Y) {
var container = Y.one("#container");
container.delegate("click", function (e) {
// Same as above
}, "li");
});
使用focus事件和blur事件
DOM的focus事件和blur事件不会冒泡。使用YUI的事件功能的fucus和blur事件可以为能获取焦点的元素分别添加focus和blur事件处理器。focus和blur事件监听DOM事件的捕获阶段(IE的focusin和focusout),使我们可以给一个元素添加一个事件监听器,就可以监听该元素中能获取焦点的后代元素触发的focus和blur事件。减少事件处理器被证明是提升页面性能的好策略,所以,使用focus和blur事件能帮助监听这俩事件的页面或应用提升性能。
创建一个focus监听器
考虑以下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>
要监听工具条中每一个按钮,传统的做法是为每一个按钮添加事件监听器。然而,使用YUI的事件功能让我们只需要为容器元素(在这里是<div id="toolbar">)添加一个监听器,任何一个按钮获取焦点时我们都会被告知。
YUI().use("event-focus", function(Y) {
var handle = Y.on("focus", function(e, arg1, arg2, etc) {
Y.log("target: " + e.target + ", arguments: " + arg1 + ", " + arg2 + ", " + etc);
// 将监听器添加给id为"toolbar"的元素,指定Y为执行环境对象,添加参数
}, "#toolbar", Y, "arg1", "arg2", "etc");
});
使用mouseenter事件和mouseleave事件
从IE的mouseenter和mouseleave事件得到启发, YUI的事件功能提供在所有A级浏览器中监听mouseenter和mouseleave的功能。对于响应mouseover和nouseout事件的DOM操作来说,使用mouseenter和mouseleave事件可以提升性能,因为这两个事件不会冒泡,对DOM的改变的频率会小很多。
创建一个mouseenter事件监听器
考虑以下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>
下面的脚本会将mouseenter事件监听器和mouseleave事件监听器添加给容器元素(<div id="container">)。当鼠标第一进入容器元素时,mouseenter事件监听函数会被调用。当鼠标第一次离开容器元素时,mouseleave事件监听函数会被调用。
YUI().use("event-mouseenter", function(Y) {
Y.on("mouseenter", function (e) {
Y.log("Mouse entered: " + this.get("id"));
}, "#container");
Y.on("mouseleave", function (e) {
Y.log("Mouse left: " + this.get("id"));
}, "#container");
});
使用touch事件
YUI的DOM事件还扩展到touch事件。要在你的应用中使用touch事件,你需要把event-touch模块包含进你的代码语句中。
YUI支持以下常用的低级touch事件,这些事件存在于大部分的有触摸功能的操作系统中:
touchstart
touchmove
touchend
touchcancel
另外,YUI也支持苹果iOS中特有的guesturestart、guesturechange、guestureend事件。目前,在其他的操作系统中,YUI还没有提供对这些事件的支持,因为它们还缺少对DOM层级多点触摸的支持。一旦这些操作系统公开在低级touch事件中的多点触摸相关信息后,我们就可以加入对多点触摸手势(multi-touch gestures)的跨平台支持。
你可以像为其他DOM事件添加监听器一样为touch事件添加监听器。在前面的DOM Events部分有说明。
touch事件的 event facade
传递给touch事件的event facade有触摸事件特有的属性:
touches
changedTouches
touchTargets
这些事件对象和传递给其他DOM监听函数的事件对象一样都是规范的。
和本地的事件对象一样,iOS中的手势事件(guesture event)的事件对象有scale和rotation属性。
跨设备的手势支持
event-guesture模块提供一组自定义事件(synthetic events),用以描述用户常用的交互手势。这组自定义事件在触摸输入设备和鼠标输入设备中都能正常工作。
编写支持触摸和鼠标输入设备的代码的开发人员就可以使用这些手势事件。拖放组件(DD)就是一个很好的例子。我们基于手势层(特别是下面说到的手势移动事件)创建拖放组件,所以在触摸设备和鼠标设备上都支持拖放组件的所有功能。
拖放组件针对手势事件编程,不管start、move、end事件是由触摸设备还是鼠标触发的。所以,同样的拖放代码在触摸设备或鼠标上都正常工作。
event-guestures模块目前有两个子模块,event-flick模块和event-move模块。将来还会添加更多跨设备的手势模块。
flick 手势事件
当用户在目标元素上发起一个flick手势flick(用手指轻弹)手势事件时,flick guesture事件被触发。
要使用flick事件,你需要使用event-flick模块,然后你就可以像监听其他DOM事件一样监听flick事件:
myNode.on("flick", function(e) {
// event facade对象上的filck事件信息
var flick = e.flick,
velocity = flick.velocity,
distance = flick.distance,
axis = flick.axis,
startX = flick.start.pageX,
startY = flick.start.pageY,
// The event object itself is the event object for
// 结束flick手势的事件(mouseup 或 touchend)
endX = e.pageX,
endY = e.pageY,
endTarget = e.target;
});
在订阅flick事件时,你可以通过第三个参数传入额外的配置信息,这些配置信息控制订阅者(监听器)得到通知的时间和方式。
// 自定义配置、没有执行环境对象、没有额外参数
myNode.on("flick", flickHandler, {
// flick超过20px而且速度大于0.8 px/ms时再发出通知
minDistance:20,
minVelocity:0.8,
// 阻止鼠标事件和触摸事件潜在的行为
preventDefault:true
});
// 自定定义配置、使用bind方法指定执行环境、额外的参数
myNode.on("flick", Y.bind(o.flickHandler, o, arg1), {
minDistance:20,
minVelocity:0.8,
preventDefault:true
});
// 使用老方法绑定执行环境和额外参数
// Flick总是预期第三个参数是flick的配置,所以不使用flick配置时,需要传入null代替。使用bind方法更清晰可靠。
myNode.on("flick", o.flickHandler, null, o, arg1);
配置参数在flick event的API文档中有详细说明。
flick事件目前不能使用事件代理。
move手势事件
move是一个更高级别的手势,该手势封装交互的开始和结束。
guesturestart、gusturemove、guestureend事件都是低级别的手势事件,用来识别鼠标或手指的”move”手势的开始、进行、结束。它们可以用作识别更高级手势的基本材料,比如”swipe”手势,详见Swipe Gesture实例。
要使用move手势事件,你需要在YUI实例中载入event-move模块,该模块支持上述的三个事件:
// 当用户把手指放在元素上或者在元素上按下鼠标时通知我
myNode.on("gesturemovestart", function(e) {...}, {
// 等待1000毫秒或者等待手指/鼠标移动超过3px,然后触发事件。
minDistance: 3,
minTime:1000,
// 如果目标元素不是select元素,阻止默认行为。
preventDefault:function(e) {
return (e.target.get("tagName").toLowerCase() !== "select");
}
});
// 当用户移动手指或者鼠标时通知我(前提是目标元素之前接收到gesturemovestart事件)。
myNode.on("gesturemove", function(e) {...});
// 当用户移动手指或者鼠标时通知我,即使document元素没有接收过gesturemovestart事件(standAlone:true)。
Y.one("document").on("gesturemove", function(e) {...}, {
standAlone:true
});
// 当用户抬起手指或者松开鼠标按钮(前提是目标元素之前接收到过gesturemovestart 事件)。
myNode.on("gesturemoveend", function(e) {...});
和flick事件一样,必须为监听器配置on方法的第三个参数。完整的配置参数说明在三个gesture move events的API文档中。
和flick事件不同,move事件可以使用事件代理(如果使用事件代理的话,配置对象从第四个参数传入,第三个参数是代理元素的过滤器)。
相关的事件
值得注意的是,三种move手势事件之间的关系和flick的不同(它们是对同一个手势的start、progress、end状态的通知)。
当编写一个需要用到move手势事件的应用时,在’start’的监听器接收到通知之前,你不希望’move’监听器收到通知;在’start’或者’move’监听器接收到通知之前,你不希望’end’监听器收到通知。这是绑定在同一个元素上的move事件的默认行为——在同一个元素上,start监听器接收到通知后,’move’和’end’监听器才会接收到通知。
然而,如上面的例子,如果你希望不管是否发生过guesturestart事件,guesturemove和guestureend时间的监听器都能得到通知(比如你动态地添加/删除后面的监听器),就可以使用standAlone:true配置。在内部,DOM监听器会监视默认绑定到document元素的mousemove/touchmove 和 mouseup/touchend。节点元素提供共享的执行环境对象来关联这三个事件。
创建虚构的DOM事件(Synthetic DOM Events)
YUI事件系统可以为元素节点定义DOM原生事件以外的新的事件。和自定义事件(custom events)类似,这些事件允许你为标识那些有意思的瞬间;和自定义事件不一样的是,虚构事件是与页面相关的,而不是与你创建的任何应用类相关。本质上,这些事件是扩展了那些能在元素节点上订阅的DOM事件。
创建虚构事件的API接口是Y.Event.define(name,config);
YUI().use("event-synthetic", function(Y) {
// 创建名为 "clickoutside"的DOM事件
Y.Event.define("clickoutside", {
// 当有人订阅这个事件时,这个函数执行
on: function (node, subscription, notifier) {
function outside(clickTarget) {
return clickTarget !== node && !clickTarget.ancestor(
function (parent) {
return parent === node;
});
}
// 安排通知器当满足某些条件时,广播clickoutside事件。典型的做法就是订阅原生DOM事件加上一些逻辑判断。
var handle = Y.one('doc').on('click', function (e) {
// 只有用户点击订阅的Node元素或者它的子元素外边时,监听函数才执行。
if (outside(e.target)) {
// 将发起该事件的原始DOM事件传递给订阅者(监听函数)
notifier.fire(e);
}
});
// 在订阅对象上储存状态数据
subscription.clickHandle = handle;
},
// 当订阅取消时,该函数被执行
detach: function (node, subscription, notifier) {
// 清除on阶段添加的DOM订阅
subscription.clickHandle.detach();
},
// 还可以定义
delegate: function (node, subscription, notifier, filter) {
...
},
// 和delegate对应的
detachDelegate: function (node, subscription, notifier, filter) {
...
}
});
// Subscribe to the synthetic event as you would any
// native DOM event
Y.on("clickoutside", function (e) {
this.addClass('hidden');
}, "#menu");
其他高级配置选项详见API文档。
使用自定义事件
YUI自定义事件系统让你可以定义和使用DOM事件以外的事件——专门针对你的应用、有利于你的应用的事件。自定义事件被设计成像DOM事件一样工作。他们可以冒泡、传递event facade、抑制传播和默认行为等。这部分叙述了YUI自定义事件的几个常见应用,还有一些实例代码。
使用Y.on的一些简单自定义事件
你可以在你代码的任何地方调用YUI实例的fire方法,发布某个有意思的瞬间的事件。
//配置YUI实例:
YUI().use('event-custom', function(Y) {
Y.fire('customapp:started', 1, 2, 3);
});
这段代码会发送通知给订阅过那个事件的函数(监听函数):
Y.on('customapp:started', function(arg1, arg2, arg3) {
Y.log('Custom App Started, now I can do a a few things);
// 参数1,2,3是由fire()提供的
});
在一个Event target的基础上定义自定义事件
创建自定义事件的常用方法就是用EventTarget augment一个对象,让这个对象成为自定义事件的宿主,成为从其他宿主冒泡过来的自定义事件的目标:
YUI().use('event-custom', function(Y) {
// 定义一个构造函数
function Publisher() {
// 创建一个自定义事件。除非你需要覆盖某事件的默认配置,否则没有必要明确地发布一个事件
this.publish("publisher:testEvent", {
// 该事件的配置项目
});
}
// 用EventTarget augment Publisher
Y.augment(Publisher, Y.EventTarget, null, null, {
//这个参数被提供给EventTarget的构造函数,让你设置在这个event target上发布的每个事件
});
// 如果你接受默认的配置,augment EventTarget如下
// Y.augment(Publisher, Y.EventTarget);
});
publish构造函数创建一个新的自定义事件。它接收一个必须参数和一个可选参数。
type – 事件名。该字符串会被传给这个是假你的监听函数,这样监听函数才知道发生可什么。
options – 你想为该自定义事件定义的配置选项。自定义时间类的大部分属性都可以在这时设定。
订阅(监听)自定义事件
要订阅一个自定义事件,需要使用on方法。下面的代码将会订阅publisher:testEvent事件:
var publisher = new Publisher();
publisher.on("publisher:testEvent", function(e) {
//事件处理函数代码
});
触发事件
要触发一个自定义事件,只需调用fire访法:
publisher.fire("publisher:testEvent");
在YUI实例之间广播事件/共享信息
当发布一个事件时,你可以指定一个广播配置——这样任意代码都知道这个事件。你可以把事件通知限制在YUI实例中,也可以全局地发布通知,让页面上的任意代码都能使用这个事件。这是在不同的YUI沙盒之间共享数据的主要办法。
var publisher = new Y.EventTarget();
publisher.name = 'broadcast publisher';
publisher.publish('instance_notification:foo', {
broadcast: 1, // 在实例级别发布事件通知
emitFacade: true // 发出facade,让我们可以访问事件目标
});
// 这个事件是可用的,可以用YUI实例订阅它
Y.on('instance_notification:foo', function(e) {
Y.log(e.target.name); // broadcast publisher
});
var publisher2 = new Y.EventTarget();
publisher2.name = 'global publisher';
publisher.publish('global_notification:foo', {
broadcast: 2, // 全局地发布事件通知
emitFacade: true // 发出facade,让我们可以访问事件目标
});
// 外部的代码,这个新的沙盒可以访问到全局的事件
YUI().use('event-custom', function(Y2) {
// 在一个特殊的event target引用上监听这个全局的事件,这个特殊的event target在YUI实例上,名为Global。
Y2.Global.on('global_notification:foo', function() {
Y.log(e.target.name); // global publisher
});
Y2.on('instance_notification:foo', function(e) {
// 将收不到通知
});
};
YUI的事件功能为响应DOM事件提供一个简单的接口,让在浏览器中创建事件驱动的应用更容易了。YUI的事件功能包包含自定义事件对象(Custom Event object),自定义事件让你可以在代码中发布(publish)某一个瞬间或某一个事件,以便页面上其他的组件能订阅(subscribe)这些事件然后响应这些事件。
YUI的事件功能包有以下功能:
DOM事件处理
自动延迟解析(deferral)赋给不可用元素的处理器
自动调整函数执行环境(scope),可选择地指定函数执行环境
将浏览器差异规范化的event facade
自动清除DOM事件监听
易用的事件代理处理
在所有A级浏览器中的事件模拟
页面加载事件(元素层级的available和contentready以及DOM层级的domready)
键盘监听功能,响应特定的组合键
获得焦点/失去焦点事件抽象层,提供代理监听这些事件的能力
冒泡(bubbleable)、可取消(cancelable)的自定义事件,有内在的AOP特性
实现可定义的DOM事件,用以描述原生事件不提供的DOM的状态
Luke Smith – 事件进化
Luke Smith对YUI3的事件系统做深入的介绍,内容包括对DOM事件、事件代理、事件模拟、自定义事件的支持。
开始
引入相关文件
为YUI的事件功能引入源文件及相关文件最简单的办法是使用如下标签将YUI种子文件添加到你的页面中。YUI实例会自己加载所需文件。
<script type="text/javascript" charset="utf-8"
src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js">
</script>
当使用’event’模块时,YUI实例会自动加载YUI的事件功能的源文件以及相关文件。让YUI实例自动加载相关文件,可以避免手工管理页面组件所需的文件列表,还可以优化初始页面大小。
如果你想手工引入所需文件,可以使用YUI Dependency Configurator工具得到所需文件列表。
YUI实例
一旦页面上有YUI种子(yui-min.js)文件后,你可以创建一个新的YUI实例,通过use方法的第一个参数指定要加载的模块。
// Create new YUI instance, and populate it with the required modules
YUI().use('event', function(Y) {
// Event available, and ready for use.
});
传给use方法的最后一个参数是一个回调函数。当YUI实例加载完页面所需的文件后,该回调函数会被调用。一旦加载完那些文件后,实现’event’模块以及它依赖的模块的类会被提供给YUI实例。被赋予功能的YUI实例的引用会通过回调函数的参数传入回调函数中。然后,你就可以在你的回调函数中,基于你配置的YUI实例编写你的应用了。
关于YUI实例的创建和use方法的更多内容,请看YUI全局对象。
DOM事件
为DOM添加事件处理器很简单。定义事件处理器(函数),把事件处理器、事件名称引用、处理器绑定到的元素这三项传递给YUI的事件功能(Event Utility):
//处理该事件的函数
function handleClick(e) {
//将event facade传给log函数输出:
Y.log(e);
}
//假设我们在页面上有一个ID为"foo"的元素:
YUI().use('node-base', function(Y) {
Y.on("click", handleClick, "#foo");
});
代码解读:
1:创建一个YUI实例——YUI的事件功能依赖于’node-base’模块,所以YUI().use(“node-base”)会加载YUI的事件功能核心特性所需的文件。如果你加载’event-base’模块,也会得到一样的功能。一些特殊的事件实现被包装成子模块,不包含在’event-base’中。这些特殊的模块在下面会讲到,可以通过它们的名字加载他们。或者直接加载’event’模块,它包含所有的DOMYUI的事件功能。
2:定义一个回调函数来处理指定事件:handleClick(e)。
3:调用YUI实例的on方法,将事件绑定到DOM元素上。on方法要求三个参数:要绑定的事件(“click” 字符串),回调函数(handleClick),还有事件绑定到的元素(“#foo”,假定元素的ID为’foo’)。
因为我们通过ID来指定元素(‘#foo’ 字符串),而不是传入Node的引用或者是HTMLElement的引用,所以可以指向一个还未存在于页面上的元素。YUI的事件功能(Event Utility)通过ID查找元素,如果找不到,在页面加载完成15秒后,会再尝试地找一次。这个“自动异步”的功能让你在某些情况下直接在你的脚本中直接编写事件处理添加代码(event attachment code),而不是需要把这些事件处理添加代码写到一个页面加载完成才执行的函数中。
使用CSS选择器语法,以数组的形式传入多个选择字符串(selector string)、以数组的形式传入Node实例、以数组的形式传入DOM元素,为多个元素添加事件处理器。
YUI().use('node-base', function(Y) {
//可以通过选择器语法选择目标元素
Y.on("click", handleClick, "#foo p"); //把#foo元素下的所有的p节点作为目标
//elements can be targeted by Node references:
var foo = Y.one("#foo");
Y.on("click", handleClick, foo);
foo.on("click", handleClick); //同上
//可以传入元素的直接引用
var foo = document.getElementById("foo");
Y.on("click", handleClick, foo);
//在所有情况下,你可以传入一个数组
Y.on("click", handleClick, ["#foo p", "#bar"]);
});
使用on方法:控制执行环境和参数
使用Y.on,需要以下参数:
1. 事件名:指向响应的DOM事件的字符串(如:“click”或“mouseover”)。开发人员经常希望能有一个所有浏览器都支持的DOM事件完整列表。但是这样的列表不存在。Danny Goodman的DHTML: The Definitive Reference 中有最完整的信息。quirksmode网站上PPK的Event Compatibility Table有最好的兼容性评价。YUI的事件功能不对你要附加处理器(监听)的事件做任何的限制,它会尝试地监听你提供的任何事件。所以,确保你针对开发的浏览器能兼容你提供的事件就是你的责任了。
2. 处理器(handler):当事件发生时调用的函数的引用。
3. 元素:如前面所说,这可以是一个或多个选择器语法的引用、Node实例、DOM元素的引用。
4. 执行环境对象:对为事件处理函数提供执行环境的对象的引用——也就是函数中this的指向。如果省略该参数,执行环境对象就是事件目标元素的Node实例。
以下是这些参数的应用实例代码:
<div id="list">
<ul>
<li id="one" class="odd">Item one</li>
<li id="two" class="even">Item two</li>
<li id="three" class="odd">Item three</li>
<li id="four" class="even">Item four</li>
</ul>
</div>
//配置YUI实例
YUI().use("dump", "node-base", function(Y) {
//随便创建一个执行环境对象
var contextObj = {
name: "context"
};
//处理点击事件的函数,输出报告信息
function handleClick(e, arg1, arg2) {
Y.log("Context object:" + Y.dump(this));
Y.log("Event facade object:" + Y.dump(e));
Y.log(arguments);
}
//让单数列表项订阅点击事件
Y.on("click", handleClick, "#list .odd", contextObj, "argumentOne", "argumentTwo");
});
运行这些代码,点击列表的第一个和第三个,Y.log会输出以下信息:
Context object: {name => context}
Event facade object: {
altKey => false,
cancelBubble => false,
ctrlKey => false,
//and remaining event facade properties
...}
最后输出的arguments对象,会包含以下三个项目:
e(event facade)、”argumentOne”(字符串)、“argumentTwo”(字符串)
以前版本的方法:Event.addListener和Event.on
YUI的事件功能包含两个添加事件监听器的两个老的方法:这两个方法包含在Event包中,遵循YUI以前版本YUI的事件功能的语法。如果你使用YUI3.x,应该避免使用这些老的方法,而是使用上面的方法。
移除事件
移除事件监听器有3种方式:
1. 为事件名参数添加事件分类前缀,在移除事件监听器时将这个字符串传给YUI的detach方法。
2. 在事件处理器对象上调用detach方法:on方法的返回值是一个事件处理器对象,该对象有一个detach方法,可以用以移除对应的事件监听器。
3. 调用YUI的detach方法,传入事件名、处理函数、元素三个参数:detach是YUI实例的方法,当你访问不到事件处理器对象时,可以使用该方法。
示例代码:
//配置YUI实例
YUI().use('node-base', function(Y) {
//定义一个事件处理函数
function handleClick(e) {
Y.log(e);
}
// 为foo元素添加事件处理器。事件名中的‘eventcategory|’部分可在移除监听器时用以识别移除哪一个事件的监听器。
var fooHandle = Y.on("eventcatgory|click", handleClick, "#foo");
// 通过事件名的前缀移除事件监听器
Y.detach('eventcategory|click');
// 通过事件处理器对象移除事件监听器
fooHandle.detach();
// 移除‘eventcategory’分类下所有的事件监听器
Y.detach('eventcategory|*');
// 通过detach方法移除
Y.detach("click", handleClick, "#foo");
// 为detach传入事件处理对象也可以移除
Y.detach(fooHandle);
});
模拟事件
模拟出来的事件是浏览器创建的事件。大部分情况下,他们的行为和用户触发的事件是一样的。模拟的事件会冒泡,事件对象有包含关于该事件数据的属性。有时候这些属性是某些浏览器专有的,所以,建议你使用Y.Event的跨浏览器方法来获取这些属性正确的值,比如target、relatedTarget、和charCode。在事件发生的过程中,事件处理器都同步地在事件目标上被调用。我们使用Y.Node实例的simulate方法来模拟事件。
鼠标事件
以下是可以模拟的7个鼠标事件:
click
dbclick
mousedown
mouseup
mouseover
mouseout
mousemove
每一个事件都是在调用simulate方法是被触发,触发时会传入两个参数:触发的事件名和指定事件额外信息的可选的对象。比如,要模拟页面body元素的点击事件,代码如下:
//配置YUI实例
YUI().use('node-event-simulate', function(Y) {
Y.one("body").simulate("click");
});
以上的代码模拟body上的click事件,事件对象上包含所有默认的属性。要给事件指定额外的信息(比如Shift键按下),必须使用第二个参数并为事件属性指定准确的DOM名(在必要时,跨浏览器逻辑会处理跨浏览器的问题)。
YUI().use('node-event-simulate', function(Y) {
Y.one("body").simulate("click", { shiftKey: true });
});
在上面更新后的代码中,一个按下Shift键并点击body元素的事件被模拟了。
根据模拟的事件的不同,需要提供的额外的属性也不同,但仅限于以下列表:
detail – 指定一个按钮被点击的次数(仅限于DOM-compliant浏览器)
screenX/screenY – 相对于屏幕,鼠标事件发生的坐标(仅限于DOM-compliant浏览器)
clientX/clientY – 相对于客户端区域,鼠标事件发生的坐标(仅限于DOM-compliant浏览器)
ctrlKey/altKey/shiftKey/metaKey – Ctrl, Alt, Shift, Meta键的状态,true为按下,false为弹起
button – 触发事件的鼠标按钮,0是左键,1是右键,2是中键
relatedTarget – 鼠标从哪个元素移动到目标元素(在mouseover和mouseout事件中)
使用不同的方法和额外属性的实例:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//模拟按下Alt 键并点击
node.simulate("click", { altKey: true});
//模拟按下Ctrl 键双击
node.simulate("dblclick", { ctrlKey: true });
//模拟鼠标经过
node.simulate("mouseover", { relatedTarget: document.body });
//模拟鼠标离开
node.simulate("mouseout", { relatedTarget: document.body });
//模拟在客户端的 (100,100) 点上按下鼠标
node.simulate("mousedown", { clientX: 100, clientY: 100 });
//模拟在客户端的 (100,100) 点上弹起鼠标
node.simulate("mouseup", { clientX: 100, clientY: 100 });
//模拟在客户端的 (200,200) 点上鼠标经过
node.simulate("mousemove", { clientX: 200, clientY: 200 });
});
键盘事件
以下是可以被模拟的键盘事件:
keyup
keydown
keypress
和鼠标一样,键盘事件也是用simulate方法来模拟。对于keyup和keydown事件,必须指定keycode属性。对于keypress事件,必须指定charCode属性。许多情况下,keyCode和charCode会用相同的值来代表相同的按键。(比如,97代表”A”键,也是字母“a”的ASCII码)。
例子:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myDiv");
//模拟按下A键
node.simulate("keydown", { keyCode: 97 });
//模拟弹起A键
node.simulate("keyup", { keyCode: 97 });
//模拟用键盘上打出 "a"
node.simulate("keypress", { charCode: 97 });
});
键盘事件还支持ctrlKey, altKey, shiftKey,metaKey事件属性。
注意:因为浏览器实现不同,键盘事件在不同浏览器中的实现方式也是不同的。比如,当在一个输入框中模拟按键按下事件,只有火狐会用按键代表的字符更新输入框。而在其他的浏览器中,事件也注册了,事件处理函数也被调用了,但是输入框中的字符和value属性都没有更新。将来这些浏览器改进对键盘事件模拟的支持后,这些问题会消失的。
UI事件
以下是可以被模拟的UI事件:
blur
change
focus
resize
scroll
select
和其他一样,UI事件也是使用simulate方法模拟的。因为UI事件没有额外的属性,所以模拟UI事件不需要给事件指定额外的信息。以下是一些实例:
YUI().use('node-event-simulate', function(Y) {
var node = Y.one("#myInput");
//simulate a change event
node.simulate("change");
//simulate a select event
node.simulate("select");
});
使用available事件和contentready事件(原来的onAvailable方法和onContentReady方法)
available让你可以定义一个函数,一旦DOM中检测到某元素时该函数就执行。这样的目的是为了减少渲染script和HTML时的时间先后问题。该事件不是为了用来给有可能存在于页面中的元素添加事件处理器的,而是为了用来在加载过程中检测元素是否可用。
该事件的用法如下:
YUI().use('node-base', function(Y) {
function TestObj(id) {
Y.on('available', this.handleOnAvailable, id, this);
}
TestObj.prototype.handleOnAvailable = function(me) {
Y.log(this.id + " is available");
}
var obj = new TestObj("myelementid");
});
<div id="myelementid">my element</div>
使用contentready事件的语法和使用available事件的语法一样,这两个事件不同的地方在于contentready会等到目标元素和它的下一个兄弟元素能响应getElementById后才触发该事件。这保证了目标元素的内容(后来通过脚本加载的内容除外)的完全加载。如果contentready检测不到目标元素的下一个兄弟元素,它将触发window.load事件。
使用domready事件(原来的onDOMReady)
domready自定义事件让你定义一个函数,该函数在页面的DOM达到一个可用的状态执行。DOM在结构完整时,才会达到可用的状态;有几个bugs,首先在IE下,如果在DOM达到结构完整时的可用状态之前,尝试通过脚本往DOM中插-入内容的话,会引起浏览器崩毁或者是页面不能成功加载。
DOM在图片加载完成之前,也可达到可用状态。所以,domready事件是window对象的load事件的一个完美替代。
YUI().use('node-base', function(Y) {
function init() {
Y.one("#hidden_element").set("visibility", "");
}
Y.on("domready", init);
// 对于所有的自定义事件,你都可以传入执行环境对象和参数,执行对象和参数最终会被传递给处理函数;
// Y.on("domready", init, contexObject, argumentOne, argumentTwo, argumentN);
});
使用key事件
key事件让你定义一个函数,该函数在某键(或组合键)被按下时执行(不管是不是有功能键【modifier】)。
创建一个按键监听器
下面的代码会为一个id为’text1′的元素添加一个按键按下事件监听器。只有返回键值(keyCode 13)被监测到时,监听函数才会执行。当检测到这个事件后,移除该监听器。
YUI().use('event-key', function(Y) {
// 保存Y.on方法的返回值,为了稍后移除监听器
var handle = Y.on('key', function(e, arg1, arg2, etc) {
Y.log(e.type + ": " + e.keyCode + ' -- ' + arg1);
// 阻止事件冒泡和阻止事件stopPropagation() and preventDefault()
e.halt();
// 删除订阅,所以该事件只发生一次
handle.detach();
// 事件监听器添加到元素'text1',指定按下事件,指定keycode为13,指定Y为执行环境对象,添加参数
}, '#text1', 'down:13', Y, "arg1", "arg2", "etc");
});
定义按键监听器的细节
在前面的例子中,’down:13′定义了按键事件监听的细节。这指定了只有返回键触发了按键按下事件,监听器才执行。指定的字符串包含三部分:
1:事件名后跟着一个冒号(‘up:’, ‘down:, or ‘press:’)
2:0个或多个被监听的keyCode,由逗号分隔。如果定义多于一个keyCode,则任意个一keyCode被监测倒都会使监听器开始执行。
3:0个或多个被监听的keyCode,由加号分隔。如果定义了功能键(modifier key),所有的键都被监测到才会使监听器开始执行。
所以,’press:65,66+shift+ctrl’这样的定义,在一个按键按下,shift和control键被按下,并且检测到keyCOde65或66时,才会触发监听器开始执行。
使用delegate方法
事件代理是指在容器元素上添加事件处理器,用以监听后代元素的交互动作。因为子元素的事件会冒泡传播到容器元素,所以这是减少事件处理器数量的稳定有效的策略(关于事件监听的更多内容请看这篇YUI博客上的文章)。
YUI的事件功能提供了一个delegate方法,可以使用CSS选择器语法来定义代理容器元素中首监听器监听的元素,这使事件代理的应用更简单了。
创建一个代理的事件监听器
考虑以下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>
使用Y.delegate方法,将要代理的事件名作为第一个参数,跟着就是监听函数,作为代理父元素的节点(监听器添加到的元素节点),最后是子元素节点,只有事件的目标元素与这些子节点匹配的时候,监听函数才会被调用。
下面的例子是绑定一个点击事件监听器到容器节点(<div id="container">),但只有事件目标是<li>的时候,监听函数才会别调用。
YUI().use("event-delegate", function(Y) {
Y.delegate("click", function(e) {
// 默认情况下,this对象指向匹配的li元素
Y.log("Default scope: " + this.get("id"));
// 如果this对象在订阅的过程中被覆盖了,该li元素也可以通过event的currentTarget属性访问到
Y.log("Clicked list item: " + e.currentTarget.get("id"));
// 真正的点击目标,可能是匹配的li或者它的子元素
Y.log("Event target: " + e.target);
// 代理父元素被添加到event facade对象中。
Y.log("Delegation container: " + e.container.get("id"));
}, "#container", "li");
});
Nodes上也有delegate方法,所以以下是另一种语法:
YUI().use("node", function(Y) {
var container = Y.one("#container");
container.delegate("click", function (e) {
// Same as above
}, "li");
});
使用focus事件和blur事件
DOM的focus事件和blur事件不会冒泡。使用YUI的事件功能的fucus和blur事件可以为能获取焦点的元素分别添加focus和blur事件处理器。focus和blur事件监听DOM事件的捕获阶段(IE的focusin和focusout),使我们可以给一个元素添加一个事件监听器,就可以监听该元素中能获取焦点的后代元素触发的focus和blur事件。减少事件处理器被证明是提升页面性能的好策略,所以,使用focus和blur事件能帮助监听这俩事件的页面或应用提升性能。
创建一个focus监听器
考虑以下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>
要监听工具条中每一个按钮,传统的做法是为每一个按钮添加事件监听器。然而,使用YUI的事件功能让我们只需要为容器元素(在这里是<div id="toolbar">)添加一个监听器,任何一个按钮获取焦点时我们都会被告知。
YUI().use("event-focus", function(Y) {
var handle = Y.on("focus", function(e, arg1, arg2, etc) {
Y.log("target: " + e.target + ", arguments: " + arg1 + ", " + arg2 + ", " + etc);
// 将监听器添加给id为"toolbar"的元素,指定Y为执行环境对象,添加参数
}, "#toolbar", Y, "arg1", "arg2", "etc");
});
使用mouseenter事件和mouseleave事件
从IE的mouseenter和mouseleave事件得到启发, YUI的事件功能提供在所有A级浏览器中监听mouseenter和mouseleave的功能。对于响应mouseover和nouseout事件的DOM操作来说,使用mouseenter和mouseleave事件可以提升性能,因为这两个事件不会冒泡,对DOM的改变的频率会小很多。
创建一个mouseenter事件监听器
考虑以下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>
下面的脚本会将mouseenter事件监听器和mouseleave事件监听器添加给容器元素(<div id="container">)。当鼠标第一进入容器元素时,mouseenter事件监听函数会被调用。当鼠标第一次离开容器元素时,mouseleave事件监听函数会被调用。
YUI().use("event-mouseenter", function(Y) {
Y.on("mouseenter", function (e) {
Y.log("Mouse entered: " + this.get("id"));
}, "#container");
Y.on("mouseleave", function (e) {
Y.log("Mouse left: " + this.get("id"));
}, "#container");
});
使用touch事件
YUI的DOM事件还扩展到touch事件。要在你的应用中使用touch事件,你需要把event-touch模块包含进你的代码语句中。
YUI支持以下常用的低级touch事件,这些事件存在于大部分的有触摸功能的操作系统中:
touchstart
touchmove
touchend
touchcancel
另外,YUI也支持苹果iOS中特有的guesturestart、guesturechange、guestureend事件。目前,在其他的操作系统中,YUI还没有提供对这些事件的支持,因为它们还缺少对DOM层级多点触摸的支持。一旦这些操作系统公开在低级touch事件中的多点触摸相关信息后,我们就可以加入对多点触摸手势(multi-touch gestures)的跨平台支持。
你可以像为其他DOM事件添加监听器一样为touch事件添加监听器。在前面的DOM Events部分有说明。
touch事件的 event facade
传递给touch事件的event facade有触摸事件特有的属性:
touches
changedTouches
touchTargets
这些事件对象和传递给其他DOM监听函数的事件对象一样都是规范的。
和本地的事件对象一样,iOS中的手势事件(guesture event)的事件对象有scale和rotation属性。
跨设备的手势支持
event-guesture模块提供一组自定义事件(synthetic events),用以描述用户常用的交互手势。这组自定义事件在触摸输入设备和鼠标输入设备中都能正常工作。
编写支持触摸和鼠标输入设备的代码的开发人员就可以使用这些手势事件。拖放组件(DD)就是一个很好的例子。我们基于手势层(特别是下面说到的手势移动事件)创建拖放组件,所以在触摸设备和鼠标设备上都支持拖放组件的所有功能。
拖放组件针对手势事件编程,不管start、move、end事件是由触摸设备还是鼠标触发的。所以,同样的拖放代码在触摸设备或鼠标上都正常工作。
event-guestures模块目前有两个子模块,event-flick模块和event-move模块。将来还会添加更多跨设备的手势模块。
flick 手势事件
当用户在目标元素上发起一个flick手势flick(用手指轻弹)手势事件时,flick guesture事件被触发。
要使用flick事件,你需要使用event-flick模块,然后你就可以像监听其他DOM事件一样监听flick事件:
myNode.on("flick", function(e) {
// event facade对象上的filck事件信息
var flick = e.flick,
velocity = flick.velocity,
distance = flick.distance,
axis = flick.axis,
startX = flick.start.pageX,
startY = flick.start.pageY,
// The event object itself is the event object for
// 结束flick手势的事件(mouseup 或 touchend)
endX = e.pageX,
endY = e.pageY,
endTarget = e.target;
});
在订阅flick事件时,你可以通过第三个参数传入额外的配置信息,这些配置信息控制订阅者(监听器)得到通知的时间和方式。
// 自定义配置、没有执行环境对象、没有额外参数
myNode.on("flick", flickHandler, {
// flick超过20px而且速度大于0.8 px/ms时再发出通知
minDistance:20,
minVelocity:0.8,
// 阻止鼠标事件和触摸事件潜在的行为
preventDefault:true
});
// 自定定义配置、使用bind方法指定执行环境、额外的参数
myNode.on("flick", Y.bind(o.flickHandler, o, arg1), {
minDistance:20,
minVelocity:0.8,
preventDefault:true
});
// 使用老方法绑定执行环境和额外参数
// Flick总是预期第三个参数是flick的配置,所以不使用flick配置时,需要传入null代替。使用bind方法更清晰可靠。
myNode.on("flick", o.flickHandler, null, o, arg1);
配置参数在flick event的API文档中有详细说明。
flick事件目前不能使用事件代理。
move手势事件
move是一个更高级别的手势,该手势封装交互的开始和结束。
guesturestart、gusturemove、guestureend事件都是低级别的手势事件,用来识别鼠标或手指的”move”手势的开始、进行、结束。它们可以用作识别更高级手势的基本材料,比如”swipe”手势,详见Swipe Gesture实例。
要使用move手势事件,你需要在YUI实例中载入event-move模块,该模块支持上述的三个事件:
// 当用户把手指放在元素上或者在元素上按下鼠标时通知我
myNode.on("gesturemovestart", function(e) {...}, {
// 等待1000毫秒或者等待手指/鼠标移动超过3px,然后触发事件。
minDistance: 3,
minTime:1000,
// 如果目标元素不是select元素,阻止默认行为。
preventDefault:function(e) {
return (e.target.get("tagName").toLowerCase() !== "select");
}
});
// 当用户移动手指或者鼠标时通知我(前提是目标元素之前接收到gesturemovestart事件)。
myNode.on("gesturemove", function(e) {...});
// 当用户移动手指或者鼠标时通知我,即使document元素没有接收过gesturemovestart事件(standAlone:true)。
Y.one("document").on("gesturemove", function(e) {...}, {
standAlone:true
});
// 当用户抬起手指或者松开鼠标按钮(前提是目标元素之前接收到过gesturemovestart 事件)。
myNode.on("gesturemoveend", function(e) {...});
和flick事件一样,必须为监听器配置on方法的第三个参数。完整的配置参数说明在三个gesture move events的API文档中。
和flick事件不同,move事件可以使用事件代理(如果使用事件代理的话,配置对象从第四个参数传入,第三个参数是代理元素的过滤器)。
相关的事件
值得注意的是,三种move手势事件之间的关系和flick的不同(它们是对同一个手势的start、progress、end状态的通知)。
当编写一个需要用到move手势事件的应用时,在’start’的监听器接收到通知之前,你不希望’move’监听器收到通知;在’start’或者’move’监听器接收到通知之前,你不希望’end’监听器收到通知。这是绑定在同一个元素上的move事件的默认行为——在同一个元素上,start监听器接收到通知后,’move’和’end’监听器才会接收到通知。
然而,如上面的例子,如果你希望不管是否发生过guesturestart事件,guesturemove和guestureend时间的监听器都能得到通知(比如你动态地添加/删除后面的监听器),就可以使用standAlone:true配置。在内部,DOM监听器会监视默认绑定到document元素的mousemove/touchmove 和 mouseup/touchend。节点元素提供共享的执行环境对象来关联这三个事件。
创建虚构的DOM事件(Synthetic DOM Events)
YUI事件系统可以为元素节点定义DOM原生事件以外的新的事件。和自定义事件(custom events)类似,这些事件允许你为标识那些有意思的瞬间;和自定义事件不一样的是,虚构事件是与页面相关的,而不是与你创建的任何应用类相关。本质上,这些事件是扩展了那些能在元素节点上订阅的DOM事件。
创建虚构事件的API接口是Y.Event.define(name,config);
YUI().use("event-synthetic", function(Y) {
// 创建名为 "clickoutside"的DOM事件
Y.Event.define("clickoutside", {
// 当有人订阅这个事件时,这个函数执行
on: function (node, subscription, notifier) {
function outside(clickTarget) {
return clickTarget !== node && !clickTarget.ancestor(
function (parent) {
return parent === node;
});
}
// 安排通知器当满足某些条件时,广播clickoutside事件。典型的做法就是订阅原生DOM事件加上一些逻辑判断。
var handle = Y.one('doc').on('click', function (e) {
// 只有用户点击订阅的Node元素或者它的子元素外边时,监听函数才执行。
if (outside(e.target)) {
// 将发起该事件的原始DOM事件传递给订阅者(监听函数)
notifier.fire(e);
}
});
// 在订阅对象上储存状态数据
subscription.clickHandle = handle;
},
// 当订阅取消时,该函数被执行
detach: function (node, subscription, notifier) {
// 清除on阶段添加的DOM订阅
subscription.clickHandle.detach();
},
// 还可以定义
delegate: function (node, subscription, notifier, filter) {
...
},
// 和delegate对应的
detachDelegate: function (node, subscription, notifier, filter) {
...
}
});
// Subscribe to the synthetic event as you would any
// native DOM event
Y.on("clickoutside", function (e) {
this.addClass('hidden');
}, "#menu");
其他高级配置选项详见API文档。
使用自定义事件
YUI自定义事件系统让你可以定义和使用DOM事件以外的事件——专门针对你的应用、有利于你的应用的事件。自定义事件被设计成像DOM事件一样工作。他们可以冒泡、传递event facade、抑制传播和默认行为等。这部分叙述了YUI自定义事件的几个常见应用,还有一些实例代码。
使用Y.on的一些简单自定义事件
你可以在你代码的任何地方调用YUI实例的fire方法,发布某个有意思的瞬间的事件。
//配置YUI实例:
YUI().use('event-custom', function(Y) {
Y.fire('customapp:started', 1, 2, 3);
});
这段代码会发送通知给订阅过那个事件的函数(监听函数):
Y.on('customapp:started', function(arg1, arg2, arg3) {
Y.log('Custom App Started, now I can do a a few things);
// 参数1,2,3是由fire()提供的
});
在一个Event target的基础上定义自定义事件
创建自定义事件的常用方法就是用EventTarget augment一个对象,让这个对象成为自定义事件的宿主,成为从其他宿主冒泡过来的自定义事件的目标:
YUI().use('event-custom', function(Y) {
// 定义一个构造函数
function Publisher() {
// 创建一个自定义事件。除非你需要覆盖某事件的默认配置,否则没有必要明确地发布一个事件
this.publish("publisher:testEvent", {
// 该事件的配置项目
});
}
// 用EventTarget augment Publisher
Y.augment(Publisher, Y.EventTarget, null, null, {
//这个参数被提供给EventTarget的构造函数,让你设置在这个event target上发布的每个事件
});
// 如果你接受默认的配置,augment EventTarget如下
// Y.augment(Publisher, Y.EventTarget);
});
publish构造函数创建一个新的自定义事件。它接收一个必须参数和一个可选参数。
type – 事件名。该字符串会被传给这个是假你的监听函数,这样监听函数才知道发生可什么。
options – 你想为该自定义事件定义的配置选项。自定义时间类的大部分属性都可以在这时设定。
订阅(监听)自定义事件
要订阅一个自定义事件,需要使用on方法。下面的代码将会订阅publisher:testEvent事件:
var publisher = new Publisher();
publisher.on("publisher:testEvent", function(e) {
//事件处理函数代码
});
触发事件
要触发一个自定义事件,只需调用fire访法:
publisher.fire("publisher:testEvent");
在YUI实例之间广播事件/共享信息
当发布一个事件时,你可以指定一个广播配置——这样任意代码都知道这个事件。你可以把事件通知限制在YUI实例中,也可以全局地发布通知,让页面上的任意代码都能使用这个事件。这是在不同的YUI沙盒之间共享数据的主要办法。
var publisher = new Y.EventTarget();
publisher.name = 'broadcast publisher';
publisher.publish('instance_notification:foo', {
broadcast: 1, // 在实例级别发布事件通知
emitFacade: true // 发出facade,让我们可以访问事件目标
});
// 这个事件是可用的,可以用YUI实例订阅它
Y.on('instance_notification:foo', function(e) {
Y.log(e.target.name); // broadcast publisher
});
var publisher2 = new Y.EventTarget();
publisher2.name = 'global publisher';
publisher.publish('global_notification:foo', {
broadcast: 2, // 全局地发布事件通知
emitFacade: true // 发出facade,让我们可以访问事件目标
});
// 外部的代码,这个新的沙盒可以访问到全局的事件
YUI().use('event-custom', function(Y2) {
// 在一个特殊的event target引用上监听这个全局的事件,这个特殊的event target在YUI实例上,名为Global。
Y2.Global.on('global_notification:foo', function() {
Y.log(e.target.name); // global publisher
});
Y2.on('instance_notification:foo', function(e) {
// 将收不到通知
});
};
发表评论
-
使用javascript动态创建SVG对象的问题
2011-04-24 01:04 2245如何在html中操作SVG对象的问题,对于嵌入式<emb ... -
直接运行html的代码
2010-12-07 17:19 888function runCode(pTargetId){ v ... -
JS正则表达式详解
2010-10-28 10:12 978JS的正则表达式 //校验是否全由数字组成 代码 va ... -
如何在事件代理中正确使用 focus 和 blur 事件
2010-10-21 22:09 1635什么是事件代理(Event Delegation)? 如果不 ... -
如何判断脚本加载完成
2010-10-21 22:04 967在“按需加载”的需求中,我们经常会判断当脚本加载完成时,返回一 ... -
JavaScript 获取事件对象的一个注意点
2010-10-21 22:00 975平时我们获取事件对象一般写法如下: function get ... -
判断 iframe 是否加载完成的完美方法
2010-10-21 21:52 975var iframe = document.createEle ... -
JS将数字转换成三位逗号分隔的样式
2010-08-02 16:33 3796function formatNumber(num){ ... -
YUI 3.0应用初探
2010-06-04 22:42 1371很惭愧。。。YUI3出来这么久了,一直都没有机会正式使用。。这 ... -
JS iframe跨域自适应内容高度
2010-02-24 11:05 2800<!DOCTYPE html PUBLIC " ... -
话说browser的脚本并行下载
2009-12-12 13:32 1380在讨论这次的主题 ... -
初涉YUI3
2009-12-11 13:44 1174study.html <!DOCTYPE HTML ... -
基於YUI2.8的 JS版多文件上传
2009-12-11 12:41 964select files: uploading: ... -
自定义滚动条
2009-11-12 19:42 985<!DOCTYPE html PUBLIC " ... -
javascript 整合的获取ID,className,tagName的方法
2009-11-12 19:40 2567var get=function(className, tag ... -
javascript 中绑定事件监听的函数【支持数组对象绑定】
2009-11-12 19:38 1208var addEventHandler=function(ob ... -
判断指定对象是否存在于另一个对象的原型链中
2009-11-12 19:35 991prototype 下的 isPrototypeOf() 方法 ... -
基于yui3如何写模块(一)
2009-11-12 19:33 954如今的前端开发越来越oo,也越来越注重重用,娴熟的用js写出o ... -
Js 数组排序【支持对象】
2009-11-12 19:30 1113//兼容 IE&FF&Safari var ... -
如何避免Javascript事件绑定出现内存泄漏
2009-11-12 19:02 1206Javascript绑定事件时,只要DOM的事件里访问不了DO ...
相关推荐
YUI3的事件系统是其强大功能之一,它允许开发者监听和处理DOM元素及自定义事件。在“yui3-master.zip”的“event”模块中,包含了丰富的事件相关的API,如`Y.on`, `Y.fire`等,它们使得事件处理更加灵活且易于维护...
这篇博文“YUI3 中tree的两种实现”探讨了如何在YUI3中创建和管理树形结构。 1. **YUI3 TreeView组件** YUI3 TreeView组件是YUI3核心库的一部分,它允许开发者创建交互式的树结构。这个组件支持节点的添加、删除、...
**YUI3 Dialog组件详解** YUI3是Yahoo!推出的一款强大的JavaScript库,它提供了丰富的UI组件和工具,用于构建高性能、跨平台的Web应用程序。Dialog组件是YUI3中的一个重要部分,它允许开发者创建可交互的弹出窗口,...
在实际使用YUI 3.17.2时,开发者可以通过`yui3-3.17.2`这个压缩包文件获取所有必要的资源。这个压缩包中包含了库的源码、示例、文档和其他辅助工具。开发者可以按照项目需求,选择合适的模块和组件进行集成。 在...
1. **模块系统**:YUI3引入了模块化设计,允许开发者按需加载组件,降低页面的初始化时间。模块可以通过`YUI.use()`方法来加载,实现了代码的异步加载和依赖管理。 2. **事件系统**:YUI的事件处理机制强大且灵活,...
YUI3的事件系统支持DOM事件绑定、解绑和触发,以及自定义事件。它还提供了一些高级特性,如事件委托,可以帮助减少事件监听器的数量,提高性能。例如,`Y.on()`用于添加事件监听器,`Y.detach()`用于移除监听器。 *...
3. **事件处理**:YUI的事件系统强大,支持事件绑定、解绑、事件冒泡等,使得用户交互编程简单易行。 4. **动画效果**:通过Transition和Anim模块,可以轻松实现平滑的CSS3动画和JavaScript动画效果。 5. **数据绑定...
2. **事件处理**:YUI3提供了强大的事件系统,支持DOM事件、自定义事件以及事件委托,使得监听和响应各种用户交互变得简单。 3. **CSS样式工具**:YUI3包含了一套CSS工具,如样式类名管理器(YUI.addClass, YUI....
YUI的事件系统强大且灵活,支持事件冒泡和事件委托,使得在大型应用中管理和组织事件变得容易。它还提供了一种机制来避免事件处理函数的重复绑定,确保性能和代码的整洁。 在对象和类的继承方面,YUI的`lang.extend...
### YUI3中文文档知识点详解 #### YUI3概述及YUIGlobal对象介绍 **YUI3** 是一个开源的JavaScript库,旨在提供一系列工具和API,帮助...无论是基本的DOM操作还是复杂的事件处理,YUI3都能提供简洁有效的解决方案。
2. **核心组件**:YUI 3的核心组件包括事件处理、DOM操作、动画效果、I/O处理等,这些都是构建交互式Web应用的基础。 3. **CSS组件**:YUI提供了丰富的CSS样式库,如Grids(网格布局)、Buttons(按钮)、Forms...
3. **事件处理**:YUI的事件系统支持事件委托、事件捕获/冒泡,以及跨浏览器的事件处理,确保在各种环境下都能正常工作。这对于基于用户交互的Ajax应用来说尤为重要。 4. **Ajax支持**:YUI包含了Ajax组件,可以...
- **事件处理**:YUI提供了一套强大的事件系统,可以轻松地监听和处理浏览器中的各种事件,如点击、鼠标移动等。 - **DOM操作**:通过YUI,开发者可以方便地进行DOM元素的选择、创建、修改和删除,大大简化了对HTML...
4. **事件系统**:YUI的事件系统支持DOM事件的监听和处理,使开发者可以方便地响应用户操作。 5. **CSS样式框架**:YUI提供了一套可自定义的CSS样式,帮助开发者快速创建一致的界面风格。 6. **DOM操作**:YUI提供了...
YUI3(Yahoo User Interface Library Version 3)是雅虎开发的一款免费开源的JavaScript库,它为开发者提供了丰富的前端开发工具,包括动画效果、事件处理、DOM操作等功能。YUI3在设计上更加模块化、可扩展性强,...
2. Event:事件处理是Web开发中的关键部分,YUI的Event模块提供了一套跨浏览器的事件处理机制,可以方便地监听和处理各种用户交互事件。 3. Connection Manager:此组件用于处理Ajax请求,提供了异步与服务器通信的...
3. **事件监听**:YUI表单验证器可能会通过监听表单元素的`onsubmit`、`onchange`等事件来进行实时验证。 4. **错误提示**:验证失败时,如何优雅地向用户展示错误信息,是用户体验的重要组成部分。 5. **自定义验证...
2. **事件处理**:YUI提供了一套完整的事件系统,可以方便地监听和处理DOM事件,以及自定义事件,增强了代码的交互性和响应性。 3. **CSS样式和布局**:YUI包含一套响应式设计的CSS框架,如Grids布局系统,帮助...
YUI 3的核心组件包括事件处理、DOM操作、动画效果、CSS样式管理、AJAX请求、数据存储以及各种用户界面组件等。 ### 版本3.10.3的特性 - **性能优化**:YUI 3.10.3版本在性能方面做了许多改进,包括更快的脚本执行...
2. **事件系统**:YUI的事件系统允许绑定和解绑事件,支持事件冒泡和事件委托,为开发者处理用户交互提供了强大支持。 3. **Ajax**:YUI提供了异步数据通信的功能,包括XMLHttpRequest对象的封装和JSONP支持,方便...