谈谈js的事件触发以及jquery的事件
sshong 发表于2013年6月20日 16:14:18 更新于2013年7月31日 10:47:55
结合上一篇讲event的日志:JavaScript基础练习源码(二)Event事件相关,由于那篇日志主要讲的是js原生的事件侦听方法,这里再谈谈js原生的事件触发方法。

说起事件event,跟通知notification总是有想通相似之处的,然而又跟消息message不一样。
几年前学习as3的时候就有过这些疑问,参见as3事件处理机制的一些缺陷

message可以认为是1对1或者1对n的有明确目标的沟通,有明确的关注目标。而event、notification则不一样,是一种观察者模式的东西,发出event、notification的主体不知道也不关心外部有没有人在观察到或者给出回应。

js的event跟as的event一样,可以通过冒泡来达到跨层级侦听的目的,其他的跟notification没有差异。都是类似观察者模式,侦听器就是观察者。

1、对于没有event的语言,可以用回调来实现notification。不同的notification用不同的字符串标示映射到不同的回调。
2、对于有event的语言,可以用event也可以用回调来实现notification。
譬如(如:flash里的PureMVC)可以用一个全局侦听器(EventDispatcher(js里叫EventTarget)支持event分发、侦听的object)来分发、侦听event,实现notification。

扯远了,回归主题,js里的event如何触发。

js里只有EventTarget这种类型的object(通常只有html里的各个element继承自他)可以分发、侦听event。
方法1:dispatchEvent的方式,先new一个Event,然后由EventTarget dispatch。
var btn = document.getElementById('btn');
var evt = document.createEvent('MouseEvent');
//evt.initEvent('click', true, true);
evt.initMouseEvent('click', true, true, document.defaultView, 0, 100, 100, 100, 100,false, false, false, false, 0, null);
//MouseEvent.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,  screenXArg, screenYArg, clientXArg, clientYArg, ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg, buttonArg, relatedTargetArg)
btn.dispatchEvent(evt);

方法2:直接调用事件名的方法来触发事件,不是所有事件都适合
// 下面这个注释拷贝自jquery的trigger源码
// Call a native DOM method on the target with the same name name as the event.
var btn = document.getElementById('btn');
btn.click();

原生的event触发就只有这两种方式了,剩下都是Notification(或者称之为模拟的event)。
jquery里的event是notification,但它模拟的比较比较好,对于eventTarget(htmlelement)分发的event支持冒泡等Event特性,对于自定义的由非EventTarget类型object分发的event则就是简单的notification。
jquery里用回调的方式来实现了notification以及自己的事件侦听机制,同时用方法2的方式来保证原生event的侦听响应。
参考前面所说,也可以用全局侦听器来实现notification,自己去想怎么实现吧。

下面是一段jquery的trigger源码,留存:
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
eventPath = [[ elem, special.bindType || type ]];
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {

    bubbleType = special.delegateType || type;
    cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
    for ( old = elem; cur; cur = cur.parentNode ) {
        eventPath.push([ cur, bubbleType ]);
        old = cur;
    }

    // Only add window if we got to document (e.g., not plain obj or detached DOM)
    if ( old === (elem.ownerDocument || document) ) {
        eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
    }
}

// Fire handlers on the event path
for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {

    cur = eventPath[i][0];
    event.type = eventPath[i][1];

    handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
    if ( handle ) {
        handle.apply( cur, data );
    }
    // Note that this is a bare JS function and not a jQuery handler
    handle = ontype && cur[ ontype ];
    if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
        event.preventDefault();
    }
}
event.type = type;

// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {

    if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
        !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {

        // Call a native DOM method on the target with the same name name as the event.
        // Can't use an .isFunction() check here because IE6/7 fails that test.
        // Don't do default actions on window, that's where global variables be (#6170)
        // IE<9 dies on focus/blur to hidden element (#1486)
        if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {

            // Don't re-trigger an onFOO event when we call its FOO() method
            old = elem[ ontype ];

            if ( old ) {
                elem[ ontype ] = null;
            }

            // Prevent re-triggering of the same event, since we already bubbled it above
            jQuery.event.triggered = type;
            elem[ type ]();
            jQuery.event.triggered = undefined;

            if ( old ) {
                elem[ ontype ] = old;
            }
        }
    }
}
标签:eventnotification分类:JS&Html5阅读:4051
评论
暂无评论
添加评论
您的大名,限长10汉字,20英文(*)
电子信箱(*)
您的网站
正文,限长500汉字,1000英文(*)
验证码(*) 单击刷新验证码
联系我
博客订阅