/**
* @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** 是一个JavaScript库,用于实现类似于百度和淘宝的输入提示补全功能。这个组件是基于KISSY框架构建的,旨在提供高效、易用且可定制的自动补全体验,适用于网页上的搜索框或者任何需要动态建议的...
KISSY.use('calendar', function(S, Calendar) { var calendar = new Calendar({ // 配置项 }); calendar.render(); }); ``` 总的来说,Kissy是一个强大且灵活的JavaScript库,特别适合那些需要快速构建复杂...
KISSY.use('sugg', function(S) { var suggest = new S.Suggest({ dataSource: ['apple', 'banana', 'cherry'], input: 'searchInput' // 指定关联的输入框元素 }); }); ``` 这里的 `dataSource` 参数定义了...
例如,使用`KISSY.Event`模块监听鼠标悬停事件,然后通过`KISSY.DOM`模块来操作DOM元素,显示或隐藏提示信息。KISSY还提供了强大的组件系统,如弹出框(Overlay)、提示框(Tip)等,这些可能被用于构建更复杂的提示...
kissy.js 提供小程序开发中一些常用的工具函数,有完整的接口文档。 下载地址:http://7te9kq.com1.z0.glb.clouddn.com/wxapp/kissydocs.html 本站下载:kissy.js (此图片来源于网络,如有侵权,请联系删除! ) 示例...
kissy-1.4.8.zip,淘宝最新前端开发包
Kissy 是一个强大的Web前端开发框架,源自阿里巴巴集团,旨在简化前端开发流程,提高开发效率。Kissy 1.4.8 版本是这个框架的一个稳定版本,它包含了丰富的功能和优化,使得开发者能够更好地应对复杂的前端项目需求...
KISSY.use('event', function (S) { S.one(window).on('scroll', function () { // 在这里处理滚动事件 }); }); ``` 2. **计算滚动位置**: 在滚动事件的回调函数中,我们需要获取当前的滚动位置。可以使用`...
【Kissy框架详解】 Kissy 是一个轻量级的JavaScript库,专为前端开发者设计,旨在简化Web开发过程,提高代码质量和效率。这个名为“Kissy 15天学会.zip”的压缩包,很可能是为了帮助初学者在15天内快速掌握Kissy...
开发者可以通过`KISSY.use()`方法来加载需要的模块,这样可以确保代码按需加载,避免资源浪费。 6. **事件监听和处理**:在前端交互中,事件监听和处理是关键。项目可能通过KISSY的事件系统绑定和触发导航项的点击...
《Kissy 文件与 KissyTeam 的前端开发实践》 Kissy 是一个轻量级的 JavaScript 框架,由 KissyTeam 团队开发并维护。这个名为 "kissyteam-kissyteam.github.com-901d2cd.rar" 的压缩包文件,包含了 KissyTeam 在 ...
2. **初始化编辑器**: 创建一个div元素作为编辑器的容器,然后通过JavaScript调用KISSY.Editor实例化编辑器,并设置相关配置。 3. **配置编辑器**: 可以设置工具栏、语言、初始内容、过滤规则等,通过配置项定制...
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, ...
通过使用KISSY.use()方法,可以加载并使用KISSY框架中的不同模块,比如node模块。 最后,教程通过一系列动手实践的示例,让学习者能够更加直观地了解和使用KISSY框架。在KISSY中,可以使用模块化的思想来组织...
KISSY.use('dom,event', function(S, DOM, Event) { var el = S.one('#myElement'); Event.on(window, 'keydown', function(e) { switch (e.keyCode) { case 37: // 左箭头 el.css('left', parseInt(el.css('...
bee-demobee-demo是由。调试模块文件使用CMD规范,是无法使用源码直接调试的,所以bee 内置了个本地静态...}KISSY.config({ packages: [ { name: 'bee-demo', base: base, ignorePackageNameInUri: true, debug: tru
这是一个基于KISSY的新人引导组件,当用户第一次访问,或用户多次访问但未销毁引导功能的时候页面会出现一个引导浮层。用户可以点击“上一个”、“下一个”、“跳过”、“完成”,四个按钮操作复层,点击右上角的...
KISSY 是一个轻量级的JavaScript库,旨在简化前端开发工作,它提供了丰富的组件和API,可以方便地进行各种前端任务,包括图片裁剪。"新增KISSY图片裁剪插件.zip"这个压缩包文件就是一个利用KISSY实现的图片裁剪功能...