`
kun10
  • 浏览: 12691 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论
  • lz12366: 没有safia环境,没法测试、、上面代码divs.apply存 ...
    YArray.test

KISSY.Event 读码笔记

阅读更多
/**
* @module  event
* @author  lifesinger@gmail.com
*/
KISSY.add('event', function(S, undef) {

    var doc = document,
        DOM = S.DOM,
        simpleAdd = doc.addEventListener ?
            function(el, type, fn, capture) {
                if (el.addEventListener) {
                    el.addEventListener(type, fn, !!capture);
                }
            } :
            function(el, type, fn) {
                if (el.attachEvent) {
                    el.attachEvent('on' + type, fn);
                }
            },
        simpleRemove = doc.removeEventListener ?
            function(el, type, fn, capture) {
                if (el.removeEventListener) {
                    el.removeEventListener(type, fn, !!capture);
                }
            } :
            function(el, type, fn) {
                if (el.detachEvent) {
                    el.detachEvent('on' + type, fn);
                }
            }, //红色部分的是原生的事件加载
        EVENT_GUID = 'ksEventTargetId',//标识符
        SPACE = ' ',
        guid = S.now(),//时间戳
        // { id: { target: el, events: { type: { handle: obj, listeners: [...] } } }, ... }
        cache = { };//缓存

    var Event = {//定义一个Event对象

        EVENT_GUID: EVENT_GUID,

        // such as: { 'mouseenter' : { fix: 'mouseover', handle: fn } }
        special: { },

        /**
         * Adds an event listener.
         * @param target {Element} An element or custom EventTarget to assign the listener to.
         * @param type {String} The type of event to append.
         * @param fn {Function} The event handler.
         * @param scope {Object} (optional) The scope (this reference) in which the handler function is executed.
         */
        add: function(target, type, fn, scope /* optional */) {//添加一个事件
            if (batch('add', target, type, fn, scope)) return;//如果需要batch做一下批量,通过batch的逻辑


            // Event.add([dom,dom])
            //getID
            var id = getID(target), isNativeEventTarget,
                special, events, eventHandle, fixedType, capture;

            // 不是有效的 target 或 参数不对
            if (id === -1 || !type || !S.isFunction(fn)) return;

            // 还没有添加过任何事件
            if (!id) {//如果目前的对象没有添加过id
                setID(target, (id = guid++));//set一个Id,并在cache里面存一个对应的对象,保存这个target和它对应的事件。
                cache[id] = {
                    target: target,
                    events: { }
                };
            }

            // 没有添加过该类型事件
            events = cache[id].events;//events用来保存这个cache的events,用events来存储一个对象对应的event对象们
            if (!events[type]) {
                isNativeEventTarget = !target.isCustomEventTarget;
                special = ((isNativeEventTarget || target._supportSpecialEvent)
                    && Event.special[type]) || { };

                eventHandle = function(event, eventData) {//eventHandle函数的定义,eventHandle是对事件添加的一层封装,原生的事件函数,只会有event这一个参数
                    if (!event || !event.fixed) {
                        event = new S.EventObject(target, event, type);//新new一个EventObject
                    }
                    if (S.isPlainObject(eventData)) {//把eventData mix到event对象上面,这里都没有区分是不是元素的事件。
                        //protect type
                        var typeo = event.type;
                        S.mix(event, eventData);
                        event.type = typeo;
                    }
                    if (special['setup']) {//如果是原生的事件或者是特殊的自定义事件,并定义了special方法,就通过special的setup方法来执行这个
                        special['setup'](event);
                    }
                    return (special.handle || Event._handle)(target, event);//返回值看special里面是否定义了handle,如果没有,就调用Event的_handle来处理target和event,默认的自定义事件的fire会来调用Event._handle方法,
                };

                events[type] = {//在events对象下面的类型下面建立对应的type的对象
                    handle: eventHandle,//每一个类型的事件的eventHandle都会保存在此一份,只不过原生的js会再用simpleAdd再做一层原生的调用
                    listeners: []
                };

                fixedType = special.fix || type;//fix capture
                capture = special['capture'];
                if (special['init']) {
                    special['init'].apply(null, S.makeArray(arguments));
                }
                if (isNativeEventTarget && special.fix !== false) {//如果是原生的事件并且fix不是false,那么就用原生的添加事件。
                    simpleAdd(target, fixedType, eventHandle, capture);
                }

            }
            // 增加 listener
            events[type].listeners.push({fn: fn, scope: scope || target});//对events对应的类型的listener下面push进对应的fn和eventHandle。
        },

        __getListeners:function(target, type) {//获取一个event对象的Listeners
            var events = Event.__getEvents(target) || {},
                eventsType,
                listeners = [];

            if ((eventsType = events[type])) {
                listeners = eventsType.listeners;
            }
            return listeners;
        },
        __getEvents:function(target) {//获取一个对象上面的事件
            var id = getID(target),c,
                events;
            if (id === -1) return; // 不是有效的 target
            if (!id || !(c = cache[id])) return; // 无 cache
            if (c.target !== target) return; // target 不匹配
            events = c.events || { };
            return events;
        },

        /**
         * Detach an event or set of events from an element.
         */
        remove: function(target, type /* optional */, fn /* optional */, scope /* optional */) {
            if (batch('remove', target, type, fn, scope)) return;

            var events = Event.__getEvents(target),
                id = getID(target),
                eventsType,
                listeners,
                len,
                i,
                j,
                t,
                isNativeEventTarget = !target.isCustomEventTarget,//isCustomEventTarget是外部传入的一个配置属性
                special = ((isNativeEventTarget || target._supportSpecialEvent)
                    && Event.special[type]) || { };


            if (events === undefined) return;
            scope = scope || target;

            if ((eventsType = events[type])) {
                listeners = eventsType.listeners;
                len = listeners.length;

                // 移除 fn
                if (S.isFunction(fn) && len) {
                    for (i = 0,j = 0,t = []; i < len; ++i) {
                        if (fn !== listeners[i].fn
                            || scope !== listeners[i].scope) {
                            t[j++] = listeners[i];
                        }
                    }
                    eventsType.listeners = t;
                    len = t.length;
                }

                // remove(el, type) or fn 已移除光
                if (fn === undef || len === 0) {
                    if (!target.isCustomEventTarget) {
                        special = Event.special[type] || { };
                        if (special.fix !== false)
                            simpleRemove(target, special.fix || type, eventsType.handle);
                    }
                    delete events[type];
                }
            }
            if (special.destroy) {
                special.destroy.apply(null, S.makeArray(arguments));
            }
            // remove(el) or type 已移除光
            if (type === undef || S.isEmptyObject(events)) {
                for (type in events) {
                    Event.remove(target, type);
                }
                delete cache[id];
                removeID(target);
            }


        },

        _handle: function(target, event) {
            /* As some listeners may remove themselves from the
             event, the original array length is dynamic. So,
             let's make a copy of all listeners, so we are
             sure we'll call all of them.*/
            var listeners = Event.__getListeners(target, event.type);
            listeners = listeners.slice(0);
            var ret,
                gRet,
                i = 0,
                len = listeners.length,
                listener;

            for (; i < len; ++i) {
                listener = listeners[i];
                ret = listener.fn.call(listener.scope, event);
                //有一个 false,最终结果就是 false
                if (gRet !== false) {
                    gRet = ret;
                }
                // 和 jQuery 逻辑保持一致
                // return false 等价 preventDefault + stopProgation
                if (ret !== undefined) {
                    event.result = ret;
                    if (ret === false) {
                        event.halt();
                    }
                }
                if (event.isImmediatePropagationStopped) {
                    break;
                }
            }

            return gRet;
        },

        _getCache: function(id) {
            return cache[id];
        },

        __getID:getID,

        _simpleAdd: simpleAdd,
        _simpleRemove: simpleRemove
    };

    // shorthand
    Event.on = Event.add;

    function batch(methodName, targets, types, fn, scope) {//batch方法,在add或者是remove之前做一层批量的处理
        // on('#id tag.className', type, fn)
        if (S.isString(targets)) {
            targets = S.query(targets);//获取targets对象
        }

        // on([targetA, targetB], type, fn)
        if (S.isArray(targets)) {//如果有多个targets,那么就在Event对象下面对应的方法下面传入参数,不处理多对象多事件的情况
            S.each(targets, function(target) {
                Event[methodName](target, types, fn, scope);
            });
            return true;
        }

        // on(target, 'click focus', fn)
        if ((types = S.trim(types)) && types.indexOf(SPACE) > 0) {//一个对象有多个事件使用同一个事件函数
            S.each(types.split(SPACE), function(type) {
                Event[methodName](targets, type, fn, scope);
            });
            return true;
        }
    }

    function getID(target) {//getID 如果是一个dom节点或一个对象,就取这个节点的EVENT_GUID属性,否则返回-1
        return isValidTarget(target) ? DOM.data(target, EVENT_GUID) : -1;
    }

    function setID(target, id) {//setID,如果是一个dom节点或一个对象,就给这个节点加上一个EVENT_GUID属性
        if (isValidTarget(target)) {
            DOM.data(target, EVENT_GUID, id);
        }
    }

    function removeID(target) {//removeID,删除一个dom节点或一个对象的EVENT_GUID属性
        DOM.removeData(target, EVENT_GUID);
    }

    function isValidTarget(target) {//isValidTarget方法
        // 3 - is text node
        // 8 - is comment node
        return target && target.nodeType !== 3 && target.nodeType !== 8;
    }

    S.Event = Event;
});

分享到:
评论

相关推荐

    KISSY.Suggest 仿百度、淘宝输入提示补全功能的组件及实例

    KISSY.Suggest 仿百度、淘宝输入提示补全功能的组件及实例!值得下载看看!资源免费,大家分享!! 更多免费资源 http://ynsky.download.csdn.net/

    Web常用UI库 kissy.zip

    Web常用UI库 kissy ,kissy 是淘宝一个开源的 JavaScript 库,包含的组件有:日历、图片放大镜、卡片切换、...

    Kissy Suggest 自动提示例子

    NULL 博文链接:https://nopainnogain.iteye.com/blog/838608

    KISSY 微信小程序版

    kissy.js 提供小程序开发中一些常用的工具函数,有完整的接口文档。 下载地址:http://7te9kq.com1.z0.glb.clouddn.com/wxapp/kissydocs.html 本站下载:kissy.js (此图片来源于网络,如有侵权,请联系删除! ) 示例...

    kissy-1.4.8.zip

    kissy-1.4.8.zip,淘宝最新前端开发包

    开源的javascript项目Kissy介绍

    本文所述的kissy是仅指其内核部分的kissy.js中的语言与框架设计思想。KISSY项目的开源网站是:http://kissyteam.github.com/ kissy怎么使用呢? 尽管在KissyUI向kissy内核化的过程中,我们提出了一些新的概念与框架...

    kissy-1.4.8.rar

    高发展前途的web前端开发利器--kissy,中文文档。拥有该文档后不必再上网到处找,一切尽在其中。

    Kissy 15天学会.zip

    Kissy 15天学会.zip欢迎下载!!!

    淘宝宝贝描述编辑器 KISSY Editor 2.0 beta

    use时, KISSY.use('gallery/pagination/1.0/pagination,gallery/pagination/1.0/tmp/friends,gallery/pagination/1.0/tmp/demo.css,gallery/pagination/1.0/assets/pagination.css', function(S, P, FriendList, ...

    bee-demo:generator-bee的demo工程,generator-bee是kissy简单工程构建器,强调简单和快速,没有复杂的工程分级和复杂的命令功能

    bee-demobee-demo是由。调试模块文件使用CMD规范,是无法使用源码直接调试的,所以bee 内置了个本地静态...}KISSY.config({ packages: [ { name: 'bee-demo', base: base, ignorePackageNameInUri: true, debug: tru

    n-guide:KISSY的一个插件,用于新手引导

    这是一个基于KISSY的新人引导组件,当用户第一次访问,或用户多次访问但未销毁引导功能的时候页面会出现一个引导浮层。用户可以点击“上一个”、“下一个”、“跳过”、“完成”,四个按钮操作复层,点击右上角的...

    Kissy学习教程

    Kissy学习教程.rarKissy学习教程.rarKissy学习教程.rarKissy学习教程.rar

    kissy源文件代码

    淘宝发布开源编辑器:KISSY Editor,和我们在 WordPress 后台使用的富文本编辑器 TinyMCE 一样,它可以让我们在线编辑和格式化文本,但是相比 TinyMCE KISSY Editor 更加轻巧,更加适合国内的网络环境。 KISSY ...

    kissy文件 kissyteam-kissyteam.github.com-901d2cd.rar

    书写特效 kissyteam-kissyteam.github.com-901d2cd.rar

    淘宝KISSY前端开发框架

    KISSY提供稳定的核心,包括 oo、dom、Event、Anim、Ajax 等;强大且易用的脚本加载器,特有的 loader;丰富的UI组件,包括 Switchable、Overlay、Draggable and Droppable 等。KISSY具备模块化、高扩展性、组件齐全...

    js KISSY框架阿里云滑动下拉导航菜单效果代码

    js KISSY框架阿里云滑动下拉导航菜单效果代码 js KISSY框架阿里云滑动下拉导航菜单效果代码 js KISSY框架阿里云滑动下拉导航菜单效果代码 js KISSY框架阿里云滑动下拉导航菜单效果代码

    KISSY 1.4.8

    KISSY 1.4.8,一个淘宝用的类似jQuery的前端框架

    kissy模块化实践

    kissy模块化实践.taobao 前端架构Kissy介绍

    kissy_editor

    KISSY Editor 是开源项目 KISSY UI Library 的一个组件。KISSY 目前基于 YUI 2.x 开发,目标是打造一系列小巧灵活、简洁实用、使用起来让人感觉愉悦的 UI 组件。目前已有 CSS 基础框架、搜索提示 Suggest 和今天发布...

Global site tag (gtag.js) - Google Analytics