- 浏览: 1162205 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
zhizhen23:
LZ 提供的链接地址失效了
重写的isPlainObject方法 -
LovingBaby:
LovingBaby 写道function fun() {}f ...
读jq之二(两种扩展) -
LovingBaby:
说的很清楚!jQuery作者为了实现简洁调用的苦心!高超的编程 ...
读jq之一(jq对象的组成) -
hard_ly:
...
将伪数组转换成数组 -
zlxzlxzlxzlxzlx:
这不能算是任意进制之间的转换,例如二十六进制、十二进制又该如何 ...
用递归实现十进制数转换N进制
十一前读了Ext core的Ext.js,这篇开始读ext-base-event.js。该文件定义了Ext.lib.Event对象,Ext.lib这个命名空间在Ext core的Ext.js中命名的。
Ext.ns("Ext.util", "Ext.lib", "Ext.data");
Ext.lib上的属性如下:
Ext.lib.Ajax
Ext.lib.Anim
Ext.lib.AnimMgr
Ext.lib.Bezier
Ext.lib.Dom
Ext.lib.Easing
Ext.lib.Event
Ext.lib.AnimBase
Ext.lib.ColorAnim
Ext.lib.Motion
Ext.lib.Scroll
Ext.lib.Event 是Ext中事件处理的轻度封装,概览下。
Ext.lib.Event = function() { var loadComplete = false, ... ... return pub; }();
可以发现仍然是一个匿名函数执行,执行后返回对象pub,pub赋值给Ext.lib.Event。再看内部细节
var loadComplete = false, unloadListeners = {}, retryCount = 0, onAvailStack = [], _interval, locked = false, win = window, doc = document, // constants POLL_RETRYS = 200, POLL_INTERVAL = 20, EL = 0, TYPE = 0, FN = 1, WFN = 2, OBJ = 2, ADJ_SCOPE = 3, SCROLLLEFT = 'scrollLeft', SCROLLTOP = 'scrollTop', UNLOAD = 'unload', MOUSEOVER = 'mouseover', MOUSEOUT = 'mouseout',
以上定义了一堆变量。window,document对象分别赋值给了win,doc。这样做的好处是减少了一层闭包。使用局部变量win,doc比直接使用window,document要快。因为它们存在于执行函数的活动对象中,解析标识符只需要查找作用域链中的单个对象。
而读取变量值的耗时是随着查找作用域链的逐层深入而不断增加。这点可参考:《JS权威指南》第五版4.7节:深入理解变量作用域。
doc后是一堆常量定义,Ext的编码习惯亦是常量全部使用大写,有多个单词时用下划线连接。接下来是一堆私有方法/函数定义,即这些函数只能在上面提到的最外层的匿名函数内使用。
// private doAdd = function() { var ret; if (win.addEventListener) { ret = function(el, eventName, fn, capture) { if (eventName == 'mouseenter') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOVER, fn, (capture)); } else if (eventName == 'mouseleave') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOUT, fn, (capture)); } else { el.addEventListener(eventName, fn, (capture)); } return fn; }; } else if (win.attachEvent) { ret = function(el, eventName, fn, capture) { el.attachEvent("on" + eventName, fn); return fn; }; } else { ret = function(){}; } return ret; }(),
doAdd,亦是一个匿名函数执行后返回新函数,用来给html元素添加事件及事件响应函数(handler)。这个函数和多数的事件添加函数差不多,用特性判断
。标准浏览器使用addEventListener添加,IE系列使用attachEvent,都不支持则返回一个空函数。这里有几点,
1,有的代码中使用特性判断时,先写win.attachEvent,后是win.addEventListener。这是不对的,应该优先使用标准的addEventListener,而IE9同时支持这两种方式。
2,这里新增了mouseenter
/mouseleave
事件,它们仅IE支持。mouseenter不同于mouseover,它是在第一次鼠标进入节点区域时触发,以后在节点区域内(子节点间)移动时不触发。Goodbye mouseover, hello mouseenter
详细讲述了使用mouseenter的好处。此处
有简单的实现。
这里为非IE浏览器间接实现了这两个事件,需要另两个函数的辅助
function checkRelatedTarget(e) { return !elContains(e.currentTarget, pub.getRelatedTarget(e)); } function elContains(parent, child) { if(parent && parent.firstChild){ while(child) { if(child === parent) { return true; } child = child.parentNode; if(child && (child.nodeType != 1)) { child = null; } } } return false; }
elContains 两个参数parent,child判断某个元素child是否是parent的子元素,是则返回true,否则false。
checkRelatedTarget 会作为一个拦截器,这里e.currentTarget IE6/7/8不支持。pub.getRelatedTarget(e)是下面封装好的方法,IE中使用fromElement,toElement。
fn = fn.createInterceptor(checkRelatedTarget);
实现的基本思路:使用mouseover事件,即当给某元素(parent)添加mouseenter事件时,鼠标移至parent时触发事件handler,但从其子元素上移动时并不触发。
顺便提下,Ext这里的elContains方法的实现明显欠妥,实际上IE中可以使用contains ,现代浏览器则可使用compareDocumentPosition ,谢谢天堂 提醒。john 写了个
function contains(a, b){ return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16); }
jQuery的选择器Sizzle.contains也是如此实现。
function getScroll() { var dd = doc.documentElement, db = doc.body; if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){ return [dd[SCROLLLEFT], dd[SCROLLTOP]]; }else if(db){ return [db[SCROLLLEFT], db[SCROLLTOP]]; }else{ return [0, 0]; } }
私有的getScroll方法返回文档的scrollTop和scrollLeft值,由于浏览器差异,该实现上先从document.documentElement取,为0后再从document.body上取。都没有返回[0,0]。
function getPageCoord (ev, xy) { ev = ev.browserEvent || ev; var coord = ev['page' + xy]; if (!coord && coord !== 0) { coord = ev['client' + xy] || 0; if (Ext.isIE) { coord += getScroll()[xy == "X" ? 0 : 1]; } } return coord; }
私有的getPageCoord方法用来获取鼠标事件时相对于文档的坐标(水平,垂直)。
Firefox引入了pageX / Y ,IE9/Safari/Chrome/Opera虽然支持但仅在文档(document)内而非页面(page)。
Safari/Chrome/Opera可以使用标准的clientX/Y获取,IE下可通过clientX/Y与scrollLeft/scrollTop计算得到。
IE9实际上也可通过clientX/Y获取,这里判断浏览器Ext.isIE在IE9正式版即将发布后明显欠妥。
再往下就是一个对象pub,匿名函数执行后会返回该对象。猜测pub是public的简写,即匿名函数执行后对外公开的接口对象(pub)。pub有以下方法
addListener: function(el, eventName, fn) { el = Ext.getDom(el); if (el && fn) { if (eventName == UNLOAD) { if (unloadListeners[el.id] === undefined) { unloadListeners[el.id] = []; } unloadListeners[el.id].push([eventName, fn]); return fn; } return doAdd(el, eventName, fn, false); } return false; },
为元素添加事件,el为添加事件的元素,eventName为事件名称(如click),fn为响应函数(hanlder)。对“unload”事件做了单独处理,内部调用私有的doAdd函数。
removeListener: function(el, eventName, fn) { el = Ext.getDom(el); var i, len, li, lis; if (el && fn) { if(eventName == UNLOAD){ if((lis = unloadListeners[el.id]) !== undefined){ for(i = 0, len = lis.length; i < len; i++){ if((li = lis[i]) && li[TYPE] == eventName && li[FN] == fn){ unloadListeners[id].splice(i, 1); } } } return; } doRemove(el, eventName, fn, false); } },
删除元素已注册的事件响应函数,参数同addListener。
这两个函数都有个注释:This function should ALWAYS be called from Ext.EventManager
可以发现,真正客户端程序员在使用Ext库时并不直接使用Ext.lib.Event.addListener / Ext.lib.Event.removeListener添加或删除事件。
而是使用Ext.EventManager.addListener / Ext.EventManager.removeListener或者它们的缩写Ext.EventManager.on / Ext.EventManager.un。
Ext.EventManager对事件管理提供了更高层次的封装。后续会介绍。
getTarget : function(ev) { ev = ev.browserEvent || ev; return this.resolveTextNode(ev.target || ev.srcElement); },
获取事件源对象。W3C标准使用 target ,IE6/7/8使用了专有的 srcElement 。令人惊奇的是Safari/Chrome/Opera也支持IE6/7/8方式,即同时支持标准和IE专有方式。Firefox仅支持标准的target,IE9beta现已支持target。
getRelatedTarget : function(ev) { ev = ev.browserEvent || ev; return this.resolveTextNode(ev.relatedTarget || (ev.type == MOUSEOUT ? ev.toElement : ev.type == MOUSEOVER ? ev.fromElement : null)); },
获取事件相关的元素。W3C标准使用 relatedTarget
,IE6/7/8使用了专有的 fromElement
/ toElement
。同样Safari/Chrome/Opera也支持IE6/7/8方式,即同时支持标准和IE专有方式。
Firefox仅支持标准的relatedTarget,IE9beta现已支持relatedTarget。
getPageX : function(ev) { return getPageCoord(ev, "X"); }, getPageY : function(ev) { return getPageCoord(ev, "Y"); }, getXY : function(ev) { return [this.getPageX(ev), this.getPageY(ev)]; },
getPageX,getPageY调用私有的getPageCoord,getPageCoord介绍如上。getXY调用getPageX,getPageY。
stopEvent : function(ev) { this.stopPropagation(ev); this.preventDefault(ev); }, stopPropagation : function(ev) { ev = ev.browserEvent || ev; if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, preventDefault : function(ev) { ev = ev.browserEvent || ev; if (ev.preventDefault) { ev.preventDefault(); } else { ev.returnValue = false; } },
这三个方法反过来说,即先说preventDefault,阻止元素的默认行为。如链接A点击,默认会跳转;input[type=submit]点击,默认会提交表单。
W3C标准使用 preventDefault
方法,IE6/7/8则是设置 returnValue
为false。Safari/Chrome/Opera同时支持IE6/7/8方式。Firefox仅支持标准的preventDefault。IE9beta现已支持preventDefault。
stopPropagation
用来停止事件冒泡。W3C标准使用stopPropagation,IE6/7/8则是设置 cancelBubble
为true。
Safari/Chrome/Opera/Firefox也支持IE方式取消冒泡。目前为止这是Firefox唯一的一个支持IE方式的属性。IE9beta现已支持stopPropagation。
stopEvent则同时阻止默认行为和事件冒泡。
getEvent : function(e) { e = e || win.event; if (!e) { var c = this.getEvent.caller; while (c) { e = c.arguments[0]; if (e && Event == e.constructor) { break; } c = c.caller; } } return e; },
getEvent顾名思义获取事件对象。W3C标准使用响应函数的第一个参数获取,IE6/7/8则使用window.event获取。
Safari/Chrome/Opera也支持IE6/7/8方式获取,IE9beta已支持W3C标准方式获取。
关于各种情形下事件对象的获取见:获取事件对象的全家
getCharCode : function(ev) { ev = ev.browserEvent || ev; return ev.charCode || ev.keyCode || 0; },
获取按键码,注意在keypress
事件中使用。键盘事件DOM2中压根没有标准化,见:Key events
因此各浏览器自行实现,Firefox/Safari/Chrome/IE9beta支持charCode,IE6/7/8/Opera不支持但使用keyCode替代。
getListeners : function(el, eventName) { Ext.EventManager.getListeners(el, eventName); }, // deprecated, call from EventManager purgeElement : function(el, recurse, eventName) { Ext.EventManager.purgeElement(el, recurse, eventName); },
这两个方法在后续讲述。
再下对load, unload做了单独处理。
Ext.lib.Event完毕。
- ext-base-event.rar (2.8 KB)
- 下载次数: 54
评论
var rd = Ext.getDom('regVerCode');
var rd0 = Ext.get(rd.parentNode);
rd0.createChild({
tag: 'img',
src: '/Captcha.jpg',
width: '80',
height: '25',
align: 'absbottom',
onclick: "this.src=getCaptcha()",
title: "点击刷新验证码"
});
确实,这也是个好处,还真没想到。
1,elContains非IE用compareDocumentPosition 更快吧~~~~
2,“使用局部变量win,doc比直接使用window,document要快。因为它们存在于执行函数的活动对象中,解析标识符只需要查找作用域链中的单个对象。
而读取变量值的耗时是随着查找作用域链的逐层深入而不断增加。”
唉,性能的最大消耗还是DOM,渲染repait、refolw(拼写有误),和网络请求。。。html不给力啊。。。
第1点,直接沿Dom树往上找速度很快的,compareDocumentPosition还实现了前后位置比较,运算量更大吧?猜测的...
第2点,前些日子翻JE上的旧帖,才知道这样做还有一个含义:
将window、document等外部(非函数作用域内)变量存于本地变量中,这样JS压缩程序就能对它们进行名称替换,获得更高的压缩率。
这点真不是一般人能想到的…… 现在写JS代码已经有意识地将用得多的外部对象存于本地变量中,这样就能成功被压缩程序混淆了,嘿嘿
1,elContains非IE用compareDocumentPosition 更快吧~~~~
2,“使用局部变量win,doc比直接使用window,document要快。因为它们存在于执行函数的活动对象中,解析标识符只需要查找作用域链中的单个对象。
而读取变量值的耗时是随着查找作用域链的逐层深入而不断增加。”
唉,性能的最大消耗还是DOM,渲染repait、refolw(拼写有误),和网络请求。。。html不给力啊。。。
发表评论
-
读Ext之十五(操作批量元素)
2011-02-07 09:14 2178前两篇读了Ext.Element,这篇介绍的Ext.Compo ... -
读Ext之十四(Ext元素)
2011-01-18 14:57 2156上篇读了Ext.Element的部分方法,这篇继续。El.ad ... -
读Ext之十三(Ext元素)
2011-01-16 16:57 1978终于越来越接近Ext的核心了。这篇开始Ext.Element, ... -
读Ext之十二(在各个位置插入元素)
2011-01-13 13:17 7758IE 除了发明 innerHTML这个快捷创建DOM元素(及其 ... -
Ext core 3.1.0的一个大Bug
2011-01-12 19:28 6497Ext core 3.1.0(下载地址 )中Ext.DomH ... -
读Ext之十一(通过innerHTML创建元素)
2011-01-09 22:19 2043innerHTML 这个由 IE 引入的属性成了事实标准, ... -
读Ext之十(解析JSON)
2011-01-03 11:36 4516首先,回到第一篇 。 ... -
读Ext之九(事件管理)
2010-12-08 08:39 2949Ext的事件管理非常强大。主要定义在Ext.EventMana ... -
读Ext之八(原生事件对象的修复及扩充)
2010-11-27 18:51 2266Ext库也对浏览器原生的事件对象做了包装,以保证兼容所有浏览器 ... -
读Ext之七(多任务定时管理)
2010-11-25 17:24 2764Ext.util.TaskRunner 用来管理多任务定时管理 ... -
读Ext之六(延迟任务的执行)
2010-11-24 17:36 3920Ext.util.DelayedTask类从名字上就可以看出它 ... -
读Ext之五(Dom的低级封装)
2010-11-14 12:08 2507上篇看了ext-base-event.js(E ... -
读Ext之三(原型扩展)
2010-09-30 09:51 3135续上篇, Ext.ns = Ext.name ... -
读Ext之二(实用方法)
2010-09-24 16:37 4936上篇看到Ext.extend,接着往下看。 Ext.n ... -
读Ext之一(实用方法)
2010-09-24 10:19 4030第一句 window.undefined = window. ...
相关推荐
常见的Linux文件系统有EXT2、EXT3、EXT4,以及现代的Btrfs和XFS等。挂载和卸载、文件权限、I/O操作等都是文件系统的重要概念。 五、网络协议栈 Linux内核包含了完整的TCP/IP协议栈,支持多种网络协议,如IP、TCP、...
当RAM不足时,可以通过关闭占用内存的功能或者优化大缓冲区来解决,如`med_ext_mem[MED_EXT_MEM_SIZE]`和`wap_mem`。 3. **四种Timer介绍** - **ID Timer**:通过`StartTimer()`启动,带ID,精度较低。 - **GUI ...
这些盘片被封装在一个无尘环境中,通过主轴电机(spindle motor)旋转,磁头通过移动臂(arm)在不同轨道(tracks)上移动来访问不同的扇区(sectors)。每个扇区是硬盘最小的存储单位,通常包含512或4096字节的数据...
在标题中的"Ruby-1.8.6.tar.gz"指的是Ruby的一个特定版本,即1.8.6,该版本被封装在一个tar.gz压缩文件中。这种格式常用于Linux和Unix系统,它结合了tar(归档)和gzip(压缩)工具,便于存储和传输大文件。 描述中...
在IT行业中,低级概念(LowLevelConcepts)通常指的是计算机系统、硬件、操作系统、编程语言等基础层面的概念。这些概念构成了所有高级软件应用的基础,是理解计算机工作原理的关键。以下是一些关于...
WebAssembly是一种低级的虚拟机指令集,设计用于在Web浏览器和其他环境中运行高性能的代码。它允许开发者使用C、C++、Rust等语言编写程序,并在多种平台上以接近原生的速度运行。Python-Wasmer作为Python的扩展,让...
1. **WebAssembly**:WebAssembly是一种低级的、类汇编的、可移植的二进制指令格式,用于在Web浏览器中运行高性能代码。Neon通过WebAssembly使C/C++代码能在JavaScript环境中运行。 2. **Neon库**:Neon库是针对...
1. **Core**: 这是 SQLAlchemy 的低级接口,提供了 SQL 表达式的构建、执行和结果处理。你可以直接操作 SQL 语句,或者使用 SQLAlchemy 的构建器来构建复杂的查询。 2. **ORM**: 对象关系映射层是 SQLAlchemy 的...
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) email = ...
例如,`open()`、`read()`、`write()`和`close()`等,这些调用封装了低级硬件交互的细节。 4. **文件操作** - 文件分配:操作系统采用不同的文件分配策略,如连续分配、链接分配、索引分配和混合分配。每种方法都...
Unix哲学强调简洁、模块化和可组合的设计原则,Rebecca OS 将这些理念融入到其设计之中。POSIX(Portable Operating System Interface)是定义了与Unix兼容的操作系统接口的一系列标准,它确保了跨平台的兼容性和互...